Passed
Push — master ( 161f5f...780ea2 )
by Robbie
02:43 queued 10s
created

tests/CommentsTest.php (27 issues)

1
<?php
2
3
namespace SilverStripe\Comments\Tests;
4
5
use HTMLPurifier_Config;
0 ignored issues
show
The type HTMLPurifier_Config was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use HTMLPurifier;
0 ignored issues
show
The type HTMLPurifier was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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;
0 ignored issues
show
The type SilverStripe\Core\Email\Email was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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(
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Dev\SapphireTest::assertDOSEquals() has been deprecated: 4.0.0:5.0.0 Use assertListEquals() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

58
        /** @scrutinizer ignore-deprecated */ $this->assertDOSEquals(array(

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

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

Loading history...
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
The call to SilverStripe\Dev\SapphireTest::assertDOSEquals() has too many arguments starting with 'Only 2 non spam posts should be shown'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
        $this->/** @scrutinizer ignore-call */ 
62
               assertDOSEquals(array(

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. Please note the @ignore annotation hint above.

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(
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Dev\SapphireTest::assertDOSEquals() has been deprecated: 4.0.0:5.0.0 Use assertListEquals() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

69
        /** @scrutinizer ignore-deprecated */ $this->assertDOSEquals(array(

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

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

Loading history...
70
            array('Name' => 'Comment 3')
71
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
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 function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

97
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

98
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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 function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

112
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

113
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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(
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Dev\SapphireTest::assertDOSEquals() has been deprecated: 4.0.0:5.0.0 Use assertListEquals() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

135
        /** @scrutinizer ignore-deprecated */ $this->assertDOSEquals(array(

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

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

Loading history...
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
The call to SilverStripe\Dev\SapphireTest::assertDOSEquals() has too many arguments starting with 'Only 2 non spam posts should be shown'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

138
        $this->/** @scrutinizer ignore-call */ 
139
               assertDOSEquals(array(

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. Please note the @ignore annotation hint above.

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(
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Dev\SapphireTest::assertDOSEquals() has been deprecated: 4.0.0:5.0.0 Use assertListEquals() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

151
        /** @scrutinizer ignore-deprecated */ $this->assertDOSEquals(array(

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

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

Loading history...
152
            array('Name' => 'Comment 3')
153
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
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 function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

177
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

178
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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 function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

202
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

203
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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 function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

216
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

217
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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 function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

230
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

231
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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
    public function testSpamComment()
270
    {
271
        // Test anonymous user
272
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

272
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

273
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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
    public function testHamComment()
315
    {
316
        // Test anonymous user
317
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

317
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

318
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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
    public function testApproveComment()
360
    {
361
        // Test anonymous user
362
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Security\Member::currentUser() has been deprecated: 5.0.0 use Security::getCurrentUser() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

362
        if ($member = /** @scrutinizer ignore-deprecated */ Member::currentUser()) {

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

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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

363
            /** @scrutinizer ignore-deprecated */ $member->logOut();

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

The explanatory message should give you some clue as to whether and when the function will be removed and what other function 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;
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');
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;
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;
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;
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");
513
        $this->assertTrue((bool)$obj->ProvideComments);
514
        $this->assertEquals('None', $obj->ModerationRequired);
515
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
516
517
        $obj = new CommentableItemEnabled();
518
        $this->assertTrue((bool)$obj->ProvideComments);
519
        $this->assertEquals('Required', $obj->ModerationRequired);
520
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
521
522
        $obj = new CommentableItemDisabled();
523
        $this->assertFalse((bool)$obj->ProvideComments);
524
        $this->assertEquals('None', $obj->ModerationRequired);
525
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
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');
538
        $this->assertFalse((bool)$obj->ProvideComments);
539
        $this->assertEquals('Required', $obj->ModerationRequired);
540
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
541
542
        $obj = new CommentableItemEnabled();
543
544
        $this->assertTrue((bool)$obj->ProvideComments);
545
        $this->assertEquals('Required', $obj->ModerationRequired);
546
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
547
548
        $obj = new CommentableItemDisabled();
549
550
        $this->assertFalse((bool)$obj->ProvideComments);
551
        $this->assertEquals('None', $obj->ModerationRequired);
552
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
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
        /** @var Comment $comment */
609
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
610
611
        $labels = $comment->FieldLabels();
612
        $expected = array(
613
            'Name' => 'Author name',
614
            'Comment' => 'Comment',
615
            'Email' => 'Email',
616
            'URL' => 'URL',
617
            'IsSpam' => 'Spam?',
618
            'Moderated' => 'Moderated?',
619
            'ParentTitle' => 'Parent',
620
            'Created' => 'Date posted',
621
        );
622
        foreach ($expected as $key => $value) {
623
            $this->assertEquals($value, $labels[$key]);
624
        }
625
    }
626
627
    public function testGetParent()
628
    {
629
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
630
        $item = $this->objFromFixture(CommentableItem::class, 'first');
631
        $parent = $comment->Parent();
632
        $this->assertSame($item->getClassName(), $parent->getClassName());
633
        $this->assertSame($item->ID, $parent->ID);
634
    }
635
636
    public function testGetParentTitle()
637
    {
638
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
639
        $title = $comment->getParentTitle();
640
        $this->assertEquals('First', $title);
641
642
        // Title from a comment with no parent is blank
643
        $comment->ParentID = 0;
644
        $comment->ParentClass = null;
645
        $comment->write();
646
        $this->assertEquals('', $comment->getParentTitle());
647
    }
648
649
    public function testGetParentClassName()
650
    {
651
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
652
        $className = $comment->getParentClassName();
653
        $this->assertEquals(CommentableItem::class, $className);
654
    }
655
656
    public function testCastingHelper()
657
    {
658
        $this->markTestSkipped('TODO');
659
    }
660
661
    public function testGetEscapedComment()
662
    {
663
        $this->markTestSkipped('TODO');
664
    }
665
666
    public function testIsPreview()
667
    {
668
        $comment = new Comment();
669
        $comment->Name = 'Fred Bloggs';
670
        $comment->Comment = 'this is a test comment';
671
        $this->assertTrue($comment->isPreview());
672
        $comment->write();
673
        $this->assertFalse($comment->isPreview());
674
    }
675
676
    public function testCanCreate()
677
    {
678
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
679
680
        // admin can create - this is always false
681
        $this->logInAs('commentadmin');
682
        $this->assertFalse($comment->canCreate());
683
684
        // visitor can view
685
        $this->logInAs('visitor');
686
        $this->assertFalse($comment->canCreate());
687
    }
688
689
    public function testCanView()
690
    {
691
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
692
693
        // admin can view
694
        $this->logInAs('commentadmin');
695
        $this->assertTrue($comment->canView());
696
697
        // visitor can view
698
        $this->logInAs('visitor');
699
        $this->assertTrue($comment->canView());
700
701
        $comment->ParentID = 0;
702
        $comment->write();
703
        $this->assertFalse($comment->canView());
704
    }
705
706
    public function testCanEdit()
707
    {
708
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
709
710
        // admin can edit
711
        $this->logInAs('commentadmin');
712
        $this->assertTrue($comment->canEdit());
713
714
        // visitor cannot
715
        $this->logInAs('visitor');
716
        $this->assertFalse($comment->canEdit());
717
718
        $comment->ParentID = 0;
719
        $comment->write();
720
        $this->assertFalse($comment->canEdit());
721
    }
722
723
    public function testCanDelete()
724
    {
725
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
726
727
        // admin can delete
728
        $this->logInAs('commentadmin');
729
        $this->assertTrue($comment->canDelete());
730
731
        // visitor cannot
732
        $this->logInAs('visitor');
733
        $this->assertFalse($comment->canDelete());
734
735
        $comment->ParentID = 0;
736
        $comment->write();
737
        $this->assertFalse($comment->canDelete());
738
    }
739
740
    public function testGetMember()
741
    {
742
        $this->logInAs('visitor');
743
        $current = Security::getCurrentUser();
744
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
745
        $method = $this->getMethod('getMember');
746
747
        // null case
748
        $member = $method->invokeArgs($comment, array());
749
        $this->assertEquals($current->ID, $member->ID);
750
751
        // numeric ID case
752
        $member = $method->invokeArgs($comment, array($current->ID));
753
        $this->assertEquals($current->ID, $member->ID);
754
755
        // identity case
756
        $member = $method->invokeArgs($comment, array($current));
757
        $this->assertEquals($current->ID, $member->ID);
758
    }
759
760
    public function testGetAuthorName()
761
    {
762
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
763
        $this->assertEquals(
764
            'FA',
765
            $comment->getAuthorName()
766
        );
767
768
        $comment->Name = '';
769
        $this->assertEquals(
770
            '',
771
            $comment->getAuthorName()
772
        );
773
774
        $author = $this->objFromFixture(Member::class, 'visitor');
775
        $comment->AuthorID = $author->ID;
776
        $comment->write();
777
        $this->assertEquals(
778
            'visitor',
779
            $comment->getAuthorName()
780
        );
781
782
        // null the names, expect null back
783
        $comment->Name = null;
784
        $comment->AuthorID = 0;
785
        $this->assertNull($comment->getAuthorName());
786
    }
787
788
789
    public function testLinks()
790
    {
791
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
792
        $this->logInAs('commentadmin');
793
794
        $method = $this->getMethod('ActionLink');
795
796
        // test with starts of strings and tokens and salts change each time
797
        $this->assertContains(
798
            '/comments/theaction/' . $comment->ID,
799
            $method->invokeArgs($comment, array('theaction'))
800
        );
801
802
        $this->assertContains(
803
            '/comments/delete/' . $comment->ID,
804
            $comment->DeleteLink()
805
        );
806
807
        $this->assertContains(
808
            '/comments/spam/' . $comment->ID,
809
            $comment->SpamLink()
810
        );
811
812
        $comment->markSpam();
813
        $this->assertContains(
814
            '/comments/ham/' . $comment->ID,
815
            $comment->HamLink()
816
        );
817
818
        //markApproved
819
        $comment->markUnapproved();
820
        $this->assertContains(
821
            '/comments/approve/' . $comment->ID,
822
            $comment->ApproveLink()
823
        );
824
    }
825
826
    public function testMarkSpam()
827
    {
828
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
829
        $comment->markSpam();
830
        $this->assertTrue($comment->Moderated);
831
        $this->assertTrue($comment->IsSpam);
832
    }
833
834
    public function testMarkApproved()
835
    {
836
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
837
        $comment->markApproved();
838
        $this->assertTrue($comment->Moderated);
839
        $this->assertFalse($comment->IsSpam);
840
    }
841
842
    public function testMarkUnapproved()
843
    {
844
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
845
        $comment->markApproved();
846
        $this->assertTrue($comment->Moderated);
847
    }
848
849
    public function testSpamClass()
850
    {
851
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
852
        $this->assertEquals('notspam', $comment->spamClass());
853
        $comment->Moderated = false;
854
        $this->assertEquals('unmoderated', $comment->spamClass());
855
        $comment->IsSpam = true;
856
        $this->assertEquals('spam', $comment->spamClass());
857
    }
858
859
    public function testGetTitle()
860
    {
861
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
862
        $this->assertEquals(
863
            'Comment by FA on First',
864
            $comment->getTitle()
865
        );
866
    }
867
868
    public function testGetCMSFields()
869
    {
870
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
871
        $fields = $comment->getCMSFields();
872
        $names = array();
873
        foreach ($fields as $field) {
874
            $names[] = $field->getName();
875
        }
876
        $expected = array(
877
            'Created',
878
            'Name',
879
            'Comment',
880
            'Email',
881
            'URL',
882
            'Options'
883
        );
884
        $this->assertEquals($expected, $names);
885
    }
886
887
    public function testGetCMSFieldsCommentHasAuthor()
888
    {
889
        $member = Member::get()->filter('FirstName', 'visitor')->first();
890
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
891
        $comment->AuthorID = $member->ID;
892
        $comment->write();
893
894
        $fields = $comment->getCMSFields();
895
        $names = array();
896
        foreach ($fields as $field) {
897
            $names[] = $field->getName();
898
        }
899
        $expected = array(
900
            'Created',
901
            'Name',
902
            'AuthorMember',
903
            'Comment',
904
            'Email',
905
            'URL',
906
            'Options'
907
        );
908
        $this->assertEquals($expected, $names);
909
    }
910
911
    public function testGetCMSFieldsWithParentComment()
912
    {
913
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
914
915
        $child = new Comment();
916
        $child->Name = 'John Smith';
917
        $child->Comment = 'This is yet another test commnent';
918
        $child->ParentCommentID = $comment->ID;
919
        $child->write();
920
921
        $fields = $child->getCMSFields();
922
        $names = array();
923
        foreach ($fields as $field) {
924
            $names[] = $field->getName();
925
        }
926
        $expected = array(
927
            'Created',
928
            'Name',
929
            'Comment',
930
            'Email',
931
            'URL',
932
            'Options',
933
            'ParentComment_Title',
934
            'ParentComment_Created',
935
            'ParentComment_AuthorName',
936
            'ParentComment_EscapedComment'
937
        );
938
        $this->assertEquals($expected, $names);
939
    }
940
941
    public function testPurifyHtml()
942
    {
943
        if (!class_exists(HTMLPurifier_Config::class)) {
944
            $this->markTestSkipped('HTMLPurifier class not found');
945
            return;
946
        }
947
948
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
949
950
        $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
951
        $this->assertEquals(
952
            'my comment',
953
            $comment->purifyHtml($dirtyHTML)
954
        );
955
    }
956
957
    public function testGravatar()
958
    {
959
        // Turn gravatars on
960
        Config::modify()->merge(CommentableItem::class, 'comments', array(
961
            'use_gravatar' => true,
962
            'gravatar_size' => 80,
963
            'gravatar_default' => 'identicon',
964
            'gravatar_rating' => 'g'
965
        ));
966
967
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
968
969
        $this->assertEquals(
970
            'https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
971
            . '=80&d=identicon&r=g',
972
            $comment->Gravatar()
973
        );
974
975
        // Turn gravatars off
976
        Config::modify()->merge(CommentableItem::class, 'comments', array(
977
            'use_gravatar' => false
978
        ));
979
980
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
981
982
        $this->assertEquals(
983
            '',
984
            $comment->Gravatar()
985
        );
986
    }
987
988
    public function testGetRepliesEnabled()
989
    {
990
        Config::modify()->merge(CommentableItem::class, 'comments', array(
991
            'nested_comments' => false
992
        ));
993
994
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
995
        $this->assertFalse($comment->getRepliesEnabled());
996
997
        Config::modify()->merge(CommentableItem::class, 'comments', array(
998
            'nested_comments' => true,
999
            'nested_depth' => 4
1000
        ));
1001
1002
        $this->assertTrue($comment->getRepliesEnabled());
1003
1004
        $comment->Depth = 4;
1005
        $this->assertFalse($comment->getRepliesEnabled());
1006
1007
1008
        // 0 indicates no limit for nested_depth
1009
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1010
            'nested_comments' => true,
1011
            'nested_depth' => 0
1012
        ));
1013
1014
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1015
        $comment->Depth = 234;
1016
1017
        $comment->markUnapproved();
1018
        $this->assertFalse($comment->getRepliesEnabled());
1019
1020
        $comment->markSpam();
1021
        $this->assertFalse($comment->getRepliesEnabled());
1022
1023
        $comment->markApproved();
1024
        $this->assertTrue($comment->getRepliesEnabled());
1025
    }
1026
1027
    public function testAllReplies()
1028
    {
1029
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1030
            'nested_comments' => true,
1031
            'nested_depth' => 4
1032
        ));
1033
1034
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1035
1036
        $this->assertEquals(
1037
            3,
1038
            $comment->allReplies()->count()
1039
        );
1040
1041
        $child = new Comment();
1042
        $child->Name = 'Fred Smith';
1043
        $child->Comment = 'This is a child comment';
1044
        $child->ParentCommentID = $comment->ID;
1045
1046
        // spam should be returned by this method
1047
        $child->markSpam();
1048
        $child->write();
1049
        $replies = $comment->allReplies();
1050
        $this->assertEquals(
1051
            4,
1052
            $comment->allReplies()->count()
1053
        );
1054
1055
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1056
            'nested_comments' => false
1057
        ));
1058
1059
        $this->assertEquals(0, $comment->allReplies()->count());
1060
    }
1061
1062
    public function testReplies()
1063
    {
1064
        CommentableItem::add_extension(CommentsExtension::class);
1065
        $this->logInWithPermission('ADMIN');
1066
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1067
            'nested_comments' => true,
1068
            'nested_depth' => 4
1069
        ));
1070
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1071
        $this->assertEquals(
1072
            3,
1073
            $comment->Replies()->count()
1074
        );
1075
1076
        // Test that spam comments are not returned
1077
        $childComment = $comment->Replies()->first();
1078
        $childComment->IsSpam = 1;
1079
        $childComment->write();
1080
        $this->assertEquals(
1081
            2,
1082
            $comment->Replies()->count()
1083
        );
1084
1085
        // Test that unmoderated comments are not returned
1086
        //
1087
        $childComment = $comment->Replies()->first();
1088
1089
        // FIXME - moderation settings scenarios need checked here
1090
        $childComment->Moderated = 0;
1091
        $childComment->IsSpam = 0;
1092
        $childComment->write();
1093
        $this->assertEquals(
1094
            2,
1095
            $comment->Replies()->count()
1096
        );
1097
1098
1099
        // Test moderation required on the front end
1100
        $item = $this->objFromFixture(CommentableItem::class, 'first');
1101
        $item->ModerationRequired = 'Required';
1102
        $item->write();
1103
1104
        Config::modify()->merge(CommentableItemDisabled::class, 'comments', array(
1105
            'nested_comments' => true,
1106
            'nested_depth' => 4,
1107
            'frontend_moderation' => true
1108
        ));
1109
1110
        $comment = DataObject::get_by_id(Comment::class, $comment->ID);
1111
1112
        $this->assertEquals(
1113
            2,
1114
            $comment->Replies()->count()
1115
        );
1116
1117
        // Turn off nesting, empty array should be returned
1118
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1119
            'nested_comments' => false
1120
        ));
1121
1122
        $this->assertEquals(
1123
            0,
1124
            $comment->Replies()->count()
1125
        );
1126
1127
        CommentableItem::remove_extension(CommentsExtension::class);
1128
    }
1129
1130
    public function testPagedReplies()
1131
    {
1132
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1133
            'nested_comments' => true,
1134
            'nested_depth' => 4,
1135
            'comments_per_page' => 2
1136
        ));
1137
1138
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1139
        $pagedList = $comment->pagedReplies();
1140
1141
        $this->assertEquals(
1142
            2,
1143
            $pagedList->TotalPages()
1144
        );
1145
1146
        $this->assertEquals(
1147
            3,
1148
            $pagedList->getTotalItems()
1149
        );
1150
1151
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1152
            'nested_comments' => false
1153
        ));
1154
1155
        $this->assertEquals(0, $comment->PagedReplies()->count());
1156
    }
1157
1158
    public function testReplyForm()
1159
    {
1160
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1161
            'nested_comments' => false,
1162
            'nested_depth' => 4
1163
        ));
1164
1165
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1166
1167
        // No nesting, no reply form
1168
        $form = $comment->replyForm();
1169
        $this->assertNull($form);
1170
1171
        // parent item so show form
1172
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1173
            'nested_comments' => true,
1174
            'nested_depth' => 4
1175
        ));
1176
        $form = $comment->ReplyForm();
1177
        $this->assertNotNull($form);
1178
        $names = array();
1179
1180
        foreach ($form->Fields() as $field) {
1181
            array_push($names, $field->getName());
1182
        }
1183
1184
        $this->assertContains('NameEmailURLComment', $names, 'The CompositeField name');
1185
        $this->assertContains('ParentID', $names);
1186
        $this->assertContains('ParentClassName', $names);
1187
        $this->assertContains('ReturnURL', $names);
1188
        $this->assertContains('ParentCommentID', $names);
1189
1190
        // no parent, no reply form
1191
1192
        $comment->ParentID = 0;
1193
        $comment->ParentClass = null;
1194
        $comment->write();
1195
        $form = $comment->replyForm();
1196
        $this->assertNull($form);
1197
    }
1198
1199
    public function testUpdateDepth()
1200
    {
1201
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1202
            'nested_comments' => true,
1203
            'nested_depth' => 4
1204
        ));
1205
1206
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1207
        $children = $comment->allReplies()->toArray();
1208
        // Make the second child a child of the first
1209
        // Make the third child a child of the second
1210
        $reply1 = $children[0];
1211
        $reply2 = $children[1];
1212
        $reply3 = $children[2];
1213
        $reply2->ParentCommentID = $reply1->ID;
1214
        $reply2->write();
1215
        $this->assertEquals(3, $reply2->Depth);
1216
        $reply3->ParentCommentID = $reply2->ID;
1217
        $reply3->write();
1218
        $this->assertEquals(4, $reply3->Depth);
1219
    }
1220
1221
    public function testGetToken()
1222
    {
1223
        $this->markTestSkipped('TODO');
1224
    }
1225
1226
    public function testMemberSalt()
1227
    {
1228
        $this->markTestSkipped('TODO');
1229
    }
1230
1231
    public function testAddToUrl()
1232
    {
1233
        $this->markTestSkipped('TODO');
1234
    }
1235
1236
    public function testCheckRequest()
1237
    {
1238
        $this->markTestSkipped('TODO');
1239
    }
1240
1241
    public function testGenerate()
1242
    {
1243
        $this->markTestSkipped('TODO');
1244
    }
1245
1246
    protected static function getMethod($name)
1247
    {
1248
        $class = new ReflectionClass(Comment::class);
1249
        $method = $class->getMethod($name);
1250
        $method->setAccessible(true);
1251
        return $method;
1252
    }
1253
}
1254