Completed
Pull Request — master (#195)
by Robbie
02:05
created

CommentsTest   D

Complexity

Total Complexity 73

Size/Duplication

Total Lines 1270
Duplicated Lines 17.72 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 73
lcom 1
cbo 10
dl 225
loc 1270
rs 4.891
c 1
b 0
f 0

54 Methods

Rating   Name   Duplication   Size   Complexity  
B setUp() 24 24 1
A tearDown() 0 5 1
B testCommentsList() 0 77 3
B testCommentCMSModerationList() 0 41 1
B testCanPostComment() 0 61 4
B testDeleteComment() 0 41 5
B testSpamComment() 44 44 2
B testHamComment() 44 44 2
B testApproveComment() 44 44 2
A testCommenterURLWrite() 0 18 2
B testSanitizesWithAllowHtml() 0 38 2
B testDefaultTemplateRendersHtmlWithAllowHtml() 0 35 2
A testDefaultEnabled() 0 49 1
A testOnBeforeDelete() 0 20 1
A testRequireDefaultRecords() 0 4 1
A testLink() 0 15 1
A testPermalink() 0 5 1
B testFieldLabels() 0 45 1
A testGetOption() 0 4 1
A testGetParent() 0 8 1
A testGetParentTitle() 12 12 1
A testGetParentClassName() 0 6 1
A testCastingHelper() 0 4 1
A testGetEscapedComment() 0 4 1
A testIsPreview() 0 9 1
A testCanCreate() 0 12 1
A testCanView() 16 16 1
A testCanEdit() 16 16 1
A testCanDelete() 16 16 1
A testGetMember() 0 19 1
B testGetAuthorName() 0 27 1
B testLinks() 0 36 1
A testMarkSpam() 0 7 1
A testMarkApproved() 0 7 1
A testMarkUnapproved() 0 6 1
A testSpamClass() 9 9 1
A testGetTitle() 0 8 1
A testGetCMSFields() 0 18 2
A testGetCMSFieldsCommentHasAuthor() 0 23 2
B testGetCMSFieldsWithParentComment() 0 29 2
A testPurifyHtml() 0 10 1
B testGravatar() 0 25 1
B testGetRepliesEnabled() 0 34 1
B testAllReplies() 0 31 1
A testReplies() 0 67 1
B testPagedReplies() 0 26 1
B testReplyForm() 0 44 2
A testUpdateDepth() 0 21 1
A testGetToken() 0 4 1
A testMemberSalt() 0 4 1
A testAddToUrl() 0 4 1
A testCheckRequest() 0 4 1
A testGenerate() 0 4 1
A getMethod() 0 7 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like CommentsTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CommentsTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SilverStripe\Comments\Tests;
4
5
use ReflectionClass;
6
use SilverStripe\Comments\Extensions\CommentsExtension;
7
use SilverStripe\Comments\Model\Comment;
8
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
9
use SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled;
10
use SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled;
11
use SilverStripe\Control\Controller;
12
use SilverStripe\Control\Director;
13
use SilverStripe\Core\Config\Config;
14
use SilverStripe\Core\Email\Email;
15
use SilverStripe\Dev\FunctionalTest;
16
use SilverStripe\Dev\TestOnly;
17
use SilverStripe\i18n\i18n;
18
use SilverStripe\ORM\DataObject;
19
use SilverStripe\Security\Member;
20
use SilverStripe\Security\Permission;
21
22
/**
23
 * @package comments
24
 */
25
class CommentsTest extends FunctionalTest
26
{
27
    
28
    public static $fixture_file = 'comments/tests/CommentsTest.yml';
29
30
    
31
    protected $extraDataObjects = array(
32
        CommentableItem::class,
33
        CommentableItemEnabled::class,
34
        CommentableItemDisabled::class
35
    );
36
37 View Code Duplication
    public function setUp()
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...
38
    {
39
        parent::setUp();
40
        Config::nest();
41
42
        // Set good default values
43
        Config::inst()->update(CommentsExtension::class, 'comments', array(
44
            'enabled' => true,
45
            'enabled_cms' => false,
46
            'require_login' => false,
47
            'require_login_cms' => false,
48
            'required_permission' => false,
49
            'require_moderation_nonmembers' => false,
50
            'require_moderation' => false,
51
            'require_moderation_cms' => false,
52
            'frontend_moderation' => false,
53
            'frontend_spam' => false,
54
        ));
55
56
        // Configure this dataobject
57
        Config::inst()->update(CommentableItem::class, 'comments', array(
58
            'enabled_cms' => true
59
        ));
60
    }
61
62
    public function tearDown()
63
    {
64
        Config::unnest();
65
        parent::tearDown();
66
    }
67
68
    public function testCommentsList()
69
    {
70
        // comments don't require moderation so unmoderated comments can be
71
        // shown but not spam posts
72
        Config::inst()->update(CommentableItem::class, 'comments', array(
73
            'require_moderation_nonmembers' => false,
74
            'require_moderation' => false,
75
            'require_moderation_cms' => false,
76
        ));
77
78
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
79
        $this->assertEquals('None', $item->ModerationRequired);
80
81
        $this->assertDOSEquals(array(
82
            array('Name' => 'Comment 1'),
83
            array('Name' => 'Comment 3')
84
        ), $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...
85
86
        // when moderated, only moderated, non spam posts should be shown.
87
        Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => true));
88
        $this->assertEquals('NonMembersOnly', $item->ModerationRequired);
89
90
        // Check that require_moderation overrides this option
91
        Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation' => true));
92
        $this->assertEquals('Required', $item->ModerationRequired);
93
94
        $this->assertDOSEquals(array(
95
            array('Name' => 'Comment 3')
96
        ), $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...
97
        $this->assertEquals(1, $item->Comments()->Count());
98
99
        // require_moderation_nonmembers still filters out unmoderated comments
100
        Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation' => false));
101
        $this->assertEquals(1, $item->Comments()->Count());
102
103
        Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => false));
104
        $this->assertEquals(2, $item->Comments()->Count());
105
106
        // With unmoderated comments set to display in frontend
107
        Config::inst()->update(CommentableItem::class, 'comments', array(
108
            'require_moderation' => true,
109
            'frontend_moderation' => true
110
        ));
111
        $this->assertEquals(1, $item->Comments()->Count());
112
113
        $this->logInWithPermission('ADMIN');
114
        $this->assertEquals(2, $item->Comments()->Count());
115
116
        // With spam comments set to display in frontend
117
        Config::inst()->update(CommentableItem::class, 'comments', array(
118
            'require_moderation' => true,
119
            'frontend_moderation' => false,
120
            'frontend_spam' => true,
121
        ));
122
        if ($member = Member::currentUser()) {
123
            $member->logOut();
124
        }
125
        $this->assertEquals(1, $item->Comments()->Count());
126
127
        $this->logInWithPermission('ADMIN');
128
        $this->assertEquals(2, $item->Comments()->Count());
129
130
131
        // With spam and unmoderated comments set to display in frontend
132
        Config::inst()->update(CommentableItem::class, 'comments', array(
133
            'require_moderation' => true,
134
            'frontend_moderation' => true,
135
            'frontend_spam' => true,
136
        ));
137
        if ($member = Member::currentUser()) {
138
            $member->logOut();
139
        }
140
        $this->assertEquals(1, $item->Comments()->Count());
141
142
        $this->logInWithPermission('ADMIN');
143
        $this->assertEquals(4, $item->Comments()->Count());
144
    }
145
146
    /**
147
     * Test moderation options configured via the CMS
148
     */
149
    public function testCommentCMSModerationList()
150
    {
151
        // comments don't require moderation so unmoderated comments can be
152
        // shown but not spam posts
153
        Config::inst()->update(CommentableItem::class, 'comments', array(
154
            'require_moderation' => true,
155
            'require_moderation_cms' => true,
156
        ));
157
158
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
159
        $this->assertEquals('None', $item->ModerationRequired);
160
161
        $this->assertDOSEquals(array(
162
            array('Name' => 'Comment 1'),
163
            array('Name' => 'Comment 3')
164
        ), $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...
165
166
        // when moderated, only moderated, non spam posts should be shown.
167
        $item->ModerationRequired = 'NonMembersOnly';
168
        $item->write();
169
        $this->assertEquals('NonMembersOnly', $item->ModerationRequired);
170
171
        // Check that require_moderation overrides this option
172
        $item->ModerationRequired = 'Required';
173
        $item->write();
174
        $this->assertEquals('Required', $item->ModerationRequired);
175
176
        $this->assertDOSEquals(array(
177
            array('Name' => 'Comment 3')
178
        ), $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...
179
        $this->assertEquals(1, $item->Comments()->Count());
180
181
        // require_moderation_nonmembers still filters out unmoderated comments
182
        $item->ModerationRequired = 'NonMembersOnly';
183
        $item->write();
184
        $this->assertEquals(1, $item->Comments()->Count());
185
186
        $item->ModerationRequired = 'None';
187
        $item->write();
188
        $this->assertEquals(2, $item->Comments()->Count());
189
    }
190
191
    public function testCanPostComment()
192
    {
193
        Config::inst()->update(CommentableItem::class, 'comments', array(
194
            'require_login' => false,
195
            'require_login_cms' => false,
196
            'required_permission' => false,
197
        ));
198
        $item = $this->objFromFixture(CommentableItem::class, 'first');
199
        $item2 = $this->objFromFixture(CommentableItem::class, 'second');
200
201
        // Test restriction free commenting
202
        if ($member = Member::currentUser()) {
203
            $member->logOut();
204
        }
205
        $this->assertFalse($item->CommentsRequireLogin);
206
        $this->assertTrue($item->canPostComment());
207
208
        // Test permission required to post
209
        Config::inst()->update(CommentableItem::class, 'comments', array(
210
            'require_login' => true,
211
            'required_permission' => 'POSTING_PERMISSION',
212
        ));
213
        $this->assertTrue($item->CommentsRequireLogin);
214
        $this->assertFalse($item->canPostComment());
215
        $this->logInWithPermission('WRONG_ONE');
216
        $this->assertFalse($item->canPostComment());
217
        $this->logInWithPermission('POSTING_PERMISSION');
218
        $this->assertTrue($item->canPostComment());
219
        $this->logInWithPermission('ADMIN');
220
        $this->assertTrue($item->canPostComment());
221
222
        // Test require login to post, but not any permissions
223
        Config::inst()->update(CommentableItem::class, 'comments', array(
224
            'required_permission' => false,
225
        ));
226
        $this->assertTrue($item->CommentsRequireLogin);
227
        if ($member = Member::currentUser()) {
228
            $member->logOut();
229
        }
230
        $this->assertFalse($item->canPostComment());
231
        $this->logInWithPermission('ANY_PERMISSION');
232
        $this->assertTrue($item->canPostComment());
233
234
        // Test options set via CMS
235
        Config::inst()->update(CommentableItem::class, 'comments', array(
236
            'require_login' => true,
237
            'require_login_cms' => true,
238
        ));
239
        $this->assertFalse($item->CommentsRequireLogin);
240
        $this->assertTrue($item2->CommentsRequireLogin);
241
        if ($member = Member::currentUser()) {
242
            $member->logOut();
243
        }
244
        $this->assertTrue($item->canPostComment());
245
        $this->assertFalse($item2->canPostComment());
246
247
        // Login grants permission to post
248
        $this->logInWithPermission('ANY_PERMISSION');
249
        $this->assertTrue($item->canPostComment());
250
        $this->assertTrue($item2->canPostComment());
251
    }
252
    public function testDeleteComment()
253
    {
254
        // Test anonymous user
255
        if ($member = Member::currentUser()) {
256
            $member->logOut();
257
        }
258
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
259
        $commentID = $comment->ID;
260
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
261
        $delete = $this->get('comments/delete/' . $comment->ID . '?ajax=1');
262
        $this->assertEquals(403, $delete->getStatusCode());
263
        $check = DataObject::get_by_id(Comment::class, $commentID);
264
        $this->assertTrue($check && $check->exists());
265
266
        // Test non-authenticated user
267
        $this->logInAs('visitor');
268
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
269
270
        // Test authenticated user
271
        $this->logInAs('commentadmin');
272
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
273
        $commentID = $comment->ID;
274
        $adminComment1Link = $comment->DeleteLink();
275
        $this->assertContains('comments/delete/' . $commentID . '?t=', $adminComment1Link);
276
277
        // Test that this link can't be shared / XSS exploited
278
        $this->logInAs('commentadmin2');
279
        $delete = $this->get($adminComment1Link);
280
        $this->assertEquals(400, $delete->getStatusCode());
281
        $check = DataObject::get_by_id(Comment::class, $commentID);
282
        $this->assertTrue($check && $check->exists());
283
284
        // Test that this other admin can delete the comment with their own link
285
        $adminComment2Link = $comment->DeleteLink();
286
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
287
        $this->autoFollowRedirection = false;
288
        $delete = $this->get($adminComment2Link);
289
        $this->assertEquals(302, $delete->getStatusCode());
290
        $check = DataObject::get_by_id(Comment::class, $commentID);
291
        $this->assertFalse($check && $check->exists());
292
    }
293
294 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...
295
    {
296
        // Test anonymous user
297
        if ($member = Member::currentUser()) {
298
            $member->logOut();
299
        }
300
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
301
        $commentID = $comment->ID;
302
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
303
        $spam = $this->get('comments/spam/'.$comment->ID.'?ajax=1');
304
        $this->assertEquals(403, $spam->getStatusCode());
305
        $check = DataObject::get_by_id(Comment::class, $commentID);
306
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
307
308
        // Test non-authenticated user
309
        $this->logInAs('visitor');
310
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
311
312
        // Test authenticated user
313
        $this->logInAs('commentadmin');
314
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
315
        $commentID = $comment->ID;
316
        $adminComment1Link = $comment->SpamLink();
317
        $this->assertContains('comments/spam/' . $commentID . '?t=', $adminComment1Link);
318
319
        // Test that this link can't be shared / XSS exploited
320
        $this->logInAs('commentadmin2');
321
        $spam = $this->get($adminComment1Link);
322
        $this->assertEquals(400, $spam->getStatusCode());
323
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
324
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
325
326
        // Test that this other admin can spam the comment with their own link
327
        $adminComment2Link = $comment->SpamLink();
328
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
329
        $this->autoFollowRedirection = false;
330
        $spam = $this->get($adminComment2Link);
331
        $this->assertEquals(302, $spam->getStatusCode());
332
        $check = DataObject::get_by_id(Comment::class, $commentID);
333
        $this->assertEquals(1, $check->IsSpam);
334
335
        // Cannot re-spam spammed comment
336
        $this->assertNull($check->SpamLink());
337
    }
338
339 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...
340
    {
341
        // Test anonymous user
342
        if ($member = Member::currentUser()) {
343
            $member->logOut();
344
        }
345
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
346
        $commentID = $comment->ID;
347
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
348
        $ham = $this->get('comments/ham/' . $comment->ID . '?ajax=1');
349
        $this->assertEquals(403, $ham->getStatusCode());
350
        $check = DataObject::get_by_id(Comment::class, $commentID);
351
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
352
353
        // Test non-authenticated user
354
        $this->logInAs('visitor');
355
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
356
357
        // Test authenticated user
358
        $this->logInAs('commentadmin');
359
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
360
        $commentID = $comment->ID;
361
        $adminComment1Link = $comment->HamLink();
362
        $this->assertContains('comments/ham/' . $commentID . '?t=', $adminComment1Link);
363
364
        // Test that this link can't be shared / XSS exploited
365
        $this->logInAs('commentadmin2');
366
        $ham = $this->get($adminComment1Link);
367
        $this->assertEquals(400, $ham->getStatusCode());
368
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
369
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
370
371
        // Test that this other admin can ham the comment with their own link
372
        $adminComment2Link = $comment->HamLink();
373
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
374
        $this->autoFollowRedirection = false;
375
        $ham = $this->get($adminComment2Link);
376
        $this->assertEquals(302, $ham->getStatusCode());
377
        $check = DataObject::get_by_id(Comment::class, $commentID);
378
        $this->assertEquals(0, $check->IsSpam);
379
380
        // Cannot re-ham hammed comment
381
        $this->assertNull($check->HamLink());
382
    }
383
384 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...
385
    {
386
        // Test anonymous user
387
        if ($member = Member::currentUser()) {
388
            $member->logOut();
389
        }
390
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
391
        $commentID = $comment->ID;
392
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
393
        $approve = $this->get('comments/approve/' . $comment->ID . '?ajax=1');
394
        $this->assertEquals(403, $approve->getStatusCode());
395
        $check = DataObject::get_by_id(Comment::class, $commentID);
396
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
397
398
        // Test non-authenticated user
399
        $this->logInAs('visitor');
400
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
401
402
        // Test authenticated user
403
        $this->logInAs('commentadmin');
404
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
405
        $commentID = $comment->ID;
406
        $adminComment1Link = $comment->ApproveLink();
407
        $this->assertContains('comments/approve/' . $commentID . '?t=', $adminComment1Link);
408
409
        // Test that this link can't be shared / XSS exploited
410
        $this->logInAs('commentadmin2');
411
        $approve = $this->get($adminComment1Link);
412
        $this->assertEquals(400, $approve->getStatusCode());
413
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
414
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
415
416
        // Test that this other admin can approve the comment with their own link
417
        $adminComment2Link = $comment->ApproveLink();
418
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
419
        $this->autoFollowRedirection = false;
420
        $approve = $this->get($adminComment2Link);
421
        $this->assertEquals(302, $approve->getStatusCode());
422
        $check = DataObject::get_by_id(Comment::class, $commentID);
423
        $this->assertEquals(1, $check->Moderated);
424
425
        // Cannot re-approve approved comment
426
        $this->assertNull($check->ApproveLink());
427
    }
428
429
    public function testCommenterURLWrite()
430
    {
431
        $comment = new Comment();
432
        // We only care about the CommenterURL, so only set that
433
        // Check a http and https URL. Add more test urls here as needed.
434
        $protocols = array(
435
            'Http',
436
            'Https',
437
        );
438
        $url = '://example.com';
439
440
        foreach ($protocols as $protocol) {
441
            $comment->CommenterURL = $protocol . $url;
442
            // The protocol should stay as if, assuming it is valid
443
            $comment->write();
444
            $this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol');
445
        }
446
    }
447
448
    public function testSanitizesWithAllowHtml()
449
    {
450
        if (!class_exists('\\HTMLPurifier')) {
451
            $this->markTestSkipped('HTMLPurifier class not found');
452
            return;
453
        }
454
455
        // Add p for paragraph
456
        // NOTE: The config method appears to append to the existing array
457
        Config::inst()->update(CommentableItem::class, 'comments', array(
458
            'html_allowed_elements' => array('p'),
459
        ));
460
461
        // Without HTML allowed
462
        $comment1 = new Comment();
463
        $comment1->AllowHtml = false;
464
        $comment1->BaseClass = CommentableItem::class;
465
        $comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
466
        $comment1->write();
467
        $this->assertEquals(
468
            '<p><script>alert("w00t")</script>my comment</p>',
469
            $comment1->Comment,
470
            'Does not remove HTML tags with html_allowed=false, ' .
471
            'which is correct behaviour because the HTML will be escaped'
472
        );
473
474
        // With HTML allowed
475
        $comment2 = new Comment();
476
        $comment2->AllowHtml = true;
477
        $comment2->ParentClass = CommentableItem::class;
478
        $comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
479
        $comment2->write();
480
        $this->assertEquals(
481
            '<p>my comment</p>',
482
            $comment2->Comment,
483
            'Removes HTML tags which are not on the whitelist'
484
        );
485
    }
486
487
    public function testDefaultTemplateRendersHtmlWithAllowHtml()
488
    {
489
        if (!class_exists('\\HTMLPurifier')) {
490
            $this->markTestSkipped('HTMLPurifier class not found');
491
        }
492
493
        Config::inst()->update(CommentableItem::class, 'comments', array(
494
            'html_allowed_elements' => array('p'),
495
        ));
496
497
        $item = new CommentableItem();
498
        $item->write();
499
500
        // Without HTML allowed
501
        $comment = new Comment();
502
        $comment->Comment = '<p>my comment</p>';
503
        $comment->AllowHtml = false;
504
        $comment->ParentID = $item->ID;
505
        $comment->BaseClass = CommentableItem::class;
506
        $comment->write();
507
508
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
509
        $this->assertContains(
510
            '&lt;p&gt;my comment&lt;/p&gt;',
511
            $html
512
        );
513
514
        $comment->AllowHtml = true;
515
        $comment->write();
516
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
517
        $this->assertContains(
518
            '<p>my comment</p>',
519
            $html
520
        );
521
    }
522
523
524
    /**
525
     * Tests whether comments are enabled or disabled by default
526
     */
527
    public function testDefaultEnabled()
528
    {
529
        // Ensure values are set via cms (not via config)
530
        Config::inst()->update(CommentableItem::class, 'comments', array(
531
            'enabled_cms' => true,
532
            'require_moderation_cms' => true,
533
            'require_login_cms' => true
534
        ));
535
536
        // With default = true
537
        $obj = new CommentableItem();
538
        $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...
539
        $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...
540
        $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...
541
        $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...
542
543
        $obj = new CommentableItemEnabled();
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
        $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...
550
        $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...
551
        $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...
552
553
        // With default = false
554
        // Because of config rules about falsey values, apply config to object directly
555
        Config::inst()->update(CommentableItem::class, 'comments', array(
556
            'enabled' => false,
557
            'require_login' => true,
558
            'require_moderation' => true
559
        ));
560
        $obj = new CommentableItem();
561
        $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...
562
        $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...
563
        $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...
564
        $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...
565
566
        $obj = new CommentableItemEnabled();
567
        $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...
568
        $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...
569
        $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...
570
571
        $obj = new CommentableItemDisabled();
572
        $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...
573
        $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...
574
        $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...
575
    }
576
577
    /*
578
    When a parent comment is deleted, remove the children
579
     */
580
    public function testOnBeforeDelete()
581
    {
582
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
583
584
        $child = new Comment();
585
        $child->Name = 'Fred Bloggs';
586
        $child->Comment = 'Child of firstComA';
587
        $child->write();
588
        $comment->ChildComments()->add($child);
589
        $this->assertEquals(4, $comment->ChildComments()->count());
590
591
        $commentID = $comment->ID;
592
        $childCommentID = $child->ID;
593
594
        $comment->delete();
595
596
        // assert that the new child been deleted
597
        $this->assertFalse(DataObject::get_by_id(Comment::class, $commentID));
598
        $this->assertFalse(DataObject::get_by_id(Comment::class, $childCommentID));
599
    }
600
601
    public function testRequireDefaultRecords()
602
    {
603
        $this->markTestSkipped('TODO');
604
    }
605
606
    public function testLink()
607
    {
608
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
609
        $this->assertEquals(
610
            'CommentableItemController#comment-' . $comment->ID,
611
            $comment->Link()
612
        );
613
        $this->assertEquals($comment->ID, $comment->ID);
614
615
        // An orphan comment has no link
616
        $comment->ParentID = 0;
617
        $comment->ParentClass = null;
618
        $comment->write();
619
        $this->assertEquals('', $comment->Link());
620
    }
621
622
    public function testPermalink()
623
    {
624
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
625
        $this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
626
    }
627
628
    /**
629
     * Test field labels in 2 languages
630
     */
631
    public function testFieldLabels()
632
    {
633
        $locale = i18n::get_locale();
634
        i18n::set_locale('fr');
635
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
636
        $labels = $comment->FieldLabels();
637
        $expected = array(
638
            'Name' => 'Nom de l\'Auteur',
639
            'Comment' => 'Commentaire',
640
            'Email' => 'Email',
641
            'URL' => 'URL',
642
            'Moderated' => 'Modéré?',
643
            'IsSpam' => 'Spam?',
644
            'AllowHtml' => 'Allow Html',
645
            'SecretToken' => 'Secret Token',
646
            'Depth' => 'Depth',
647
            'Author' => 'Author Member',
648
            'ParentComment' => 'Parent Comment',
649
            'ChildComments' => 'Child Comments',
650
            'ParentTitle' => 'Parent',
651
            'Created' => 'Date de publication',
652
            'Parent' => 'Parent'
653
        );
654
        i18n::set_locale($locale);
655
        $this->assertEquals($expected, $labels);
656
        $labels = $comment->FieldLabels();
657
        $expected = array(
658
            'Name' => 'Author Name',
659
            'Comment' => 'Comment',
660
            'Email' => 'Email',
661
            'URL' => 'URL',
662
            'Moderated' => 'Moderated?',
663
            'IsSpam' => 'Spam?',
664
            'AllowHtml' => 'Allow Html',
665
            'SecretToken' => 'Secret Token',
666
            'Depth' => 'Depth',
667
            'Author' => 'Author Member',
668
            'ParentComment' => 'Parent Comment',
669
            'ChildComments' => 'Child Comments',
670
            'ParentTitle' => 'Parent',
671
            'Created' => 'Date posted',
672
            'Parent' => 'Parent'
673
        );
674
        $this->assertEquals($expected, $labels);
675
    }
676
677
    public function testGetOption()
678
    {
679
        $this->markTestSkipped('TODO');
680
    }
681
682
    public function testGetParent()
683
    {
684
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
685
        $item = $this->objFromFixture(CommentableItem::class, 'first');
686
        $parent = $comment->Parent();
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean parentClass()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
687
        $this->assertSame($item->getClassName(), $parent->getClassName());
688
        $this->assertSame($item->ID, $parent->ID);
689
    }
690
691 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...
692
    {
693
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
694
        $title = $comment->getParentTitle();
695
        $this->assertEquals('First', $title);
696
697
        // Title from a comment with no parent is blank
698
        $comment->ParentID = 0;
699
        $comment->ParentClass = null;
700
        $comment->write();
701
        $this->assertEquals('', $comment->getParentTitle());
702
    }
703
704
    public function testGetParentClassName()
705
    {
706
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
707
        $className = $comment->getParentClassName();
0 ignored issues
show
Bug introduced by
The method getParentClassName() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean parentClass()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
708
        $this->assertEquals(CommentableItem::class, $className);
709
    }
710
711
    public function testCastingHelper()
712
    {
713
        $this->markTestSkipped('TODO');
714
    }
715
716
    public function testGetEscapedComment()
717
    {
718
        $this->markTestSkipped('TODO');
719
    }
720
721
    public function testIsPreview()
722
    {
723
        $comment = new Comment();
724
        $comment->Name = 'Fred Bloggs';
725
        $comment->Comment = 'this is a test comment';
726
        $this->assertTrue($comment->isPreview());
727
        $comment->write();
728
        $this->assertFalse($comment->isPreview());
729
    }
730
731
    public function testCanCreate()
732
    {
733
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
734
735
        // admin can create - this is always false
736
        $this->logInAs('commentadmin');
737
        $this->assertFalse($comment->canCreate());
738
739
        // visitor can view
740
        $this->logInAs('visitor');
741
        $this->assertFalse($comment->canCreate());
742
    }
743
744 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...
745
    {
746
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
747
748
        // admin can view
749
        $this->logInAs('commentadmin');
750
        $this->assertTrue($comment->canView());
751
752
        // visitor can view
753
        $this->logInAs('visitor');
754
        $this->assertTrue($comment->canView());
755
756
        $comment->ParentID = 0;
757
        $comment->write();
758
        $this->assertFalse($comment->canView());
759
    }
760
761 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...
762
    {
763
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
764
765
        // admin can edit
766
        $this->logInAs('commentadmin');
767
        $this->assertTrue($comment->canEdit());
768
769
        // visitor cannot
770
        $this->logInAs('visitor');
771
        $this->assertFalse($comment->canEdit());
772
773
        $comment->ParentID = 0;
774
        $comment->write();
775
        $this->assertFalse($comment->canEdit());
776
    }
777
778 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...
779
    {
780
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
781
782
        // admin can delete
783
        $this->logInAs('commentadmin');
784
        $this->assertTrue($comment->canDelete());
785
786
        // visitor cannot
787
        $this->logInAs('visitor');
788
        $this->assertFalse($comment->canDelete());
789
790
        $comment->ParentID = 0;
791
        $comment->write();
792
        $this->assertFalse($comment->canDelete());
793
    }
794
795
    public function testGetMember()
796
    {
797
        $this->logInAs('visitor');
798
        $current = Member::currentUser();
799
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
800
        $method = $this->getMethod('getMember');
801
802
        // null case
803
        $member = $method->invokeArgs($comment, array());
804
        $this->assertEquals($current, $member);
805
806
        // numeric ID case
807
        $member = $method->invokeArgs($comment, array($current->ID));
808
        $this->assertEquals($current, $member);
809
810
        // identity case
811
        $member = $method->invokeArgs($comment, array($current));
812
        $this->assertEquals($current, $member);
813
    }
814
815
    public function testGetAuthorName()
816
    {
817
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
818
        $this->assertEquals(
819
            'FA',
820
            $comment->getAuthorName()
821
        );
822
823
        $comment->Name = '';
824
        $this->assertEquals(
825
            '',
826
            $comment->getAuthorName()
827
        );
828
829
        $author = $this->objFromFixture(Member::class, 'visitor');
830
        $comment->AuthorID = $author->ID;
831
        $comment->write();
832
        $this->assertEquals(
833
            'visitor',
834
            $comment->getAuthorName()
835
        );
836
837
        // null the names, expect null back
838
        $comment->Name = null;
839
        $comment->AuthorID = 0;
840
        $this->assertNull($comment->getAuthorName());
841
    }
842
843
844
    public function testLinks()
845
    {
846
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
847
        $this->logInAs('commentadmin');
848
849
        $method = $this->getMethod('ActionLink');
850
851
        // test with starts of strings and tokens and salts change each time
852
        $this->assertStringStartsWith(
853
            '/comments/theaction/' . $comment->ID,
854
            $method->invokeArgs($comment, array('theaction'))
855
        );
856
857
        $this->assertStringStartsWith(
858
            '/comments/delete/' . $comment->ID,
859
            $comment->DeleteLink()
860
        );
861
862
        $this->assertStringStartsWith(
863
            '/comments/spam/' . $comment->ID,
864
            $comment->SpamLink()
865
        );
866
867
        $comment->markSpam();
868
        $this->assertStringStartsWith(
869
            '/comments/ham/' . $comment->ID,
870
            $comment->HamLink()
871
        );
872
873
        //markApproved
874
        $comment->markUnapproved();
875
        $this->assertStringStartsWith(
876
            '/comments/approve/' . $comment->ID,
877
            $comment->ApproveLink()
878
        );
879
    }
880
881
    public function testMarkSpam()
882
    {
883
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
884
        $comment->markSpam();
885
        $this->assertTrue($comment->Moderated);
886
        $this->assertTrue($comment->IsSpam);
887
    }
888
889
    public function testMarkApproved()
890
    {
891
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
892
        $comment->markApproved();
893
        $this->assertTrue($comment->Moderated);
894
        $this->assertFalse($comment->IsSpam);
895
    }
896
897
    public function testMarkUnapproved()
898
    {
899
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
900
        $comment->markApproved();
901
        $this->assertTrue($comment->Moderated);
902
    }
903
904 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...
905
    {
906
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
907
        $this->assertEquals('notspam', $comment->spamClass());
908
        $comment->Moderated = false;
909
        $this->assertEquals('unmoderated', $comment->spamClass());
910
        $comment->IsSpam = true;
911
        $this->assertEquals('spam', $comment->spamClass());
912
    }
913
914
    public function testGetTitle()
915
    {
916
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
917
        $this->assertEquals(
918
            'Comment by FA on First',
919
            $comment->getTitle()
920
        );
921
    }
922
923
    public function testGetCMSFields()
924
    {
925
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
926
        $fields = $comment->getCMSFields();
927
        $names = array();
928
        foreach ($fields as $field) {
929
            $names[] = $field->getName();
930
        }
931
        $expected = array(
932
            'Created',
933
            'Name',
934
            'Comment',
935
            'Email',
936
            'URL',
937
            'Options'
938
        );
939
        $this->assertEquals($expected, $names);
940
    }
941
942
    public function testGetCMSFieldsCommentHasAuthor()
943
    {
944
        $member = Member::get()->filter('FirstName', 'visitor')->first();
945
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
946
        $comment->AuthorID = $member->ID;
947
        $comment->write();
948
949
        $fields = $comment->getCMSFields();
950
        $names = array();
951
        foreach ($fields as $field) {
952
            $names[] = $field->getName();
953
        }
954
        $expected = array(
955
            'Created',
956
            'Name',
957
            'AuthorMember',
958
            'Comment',
959
            'Email',
960
            'URL',
961
            'Options'
962
        );
963
        $this->assertEquals($expected, $names);
964
    }
965
966
    public function testGetCMSFieldsWithParentComment()
967
    {
968
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
969
970
        $child = new Comment();
971
        $child->Name = 'John Smith';
972
        $child->Comment = 'This is yet another test commnent';
973
        $child->ParentCommentID = $comment->ID;
974
        $child->write();
975
976
        $fields = $child->getCMSFields();
977
        $names = array();
978
        foreach ($fields as $field) {
979
            $names[] = $field->getName();
980
        }
981
        $expected = array(
982
            'Created',
983
            'Name',
984
            'Comment',
985
            'Email',
986
            'URL',
987
            'Options',
988
            'ParentComment_Title',
989
            'ParentComment_Created',
990
            'ParentComment_AuthorName',
991
            'ParentComment_EscapedComment'
992
        );
993
        $this->assertEquals($expected, $names);
994
    }
995
996
    public function testPurifyHtml()
997
    {
998
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
999
1000
        $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
1001
        $this->assertEquals(
1002
            'my comment',
1003
            $comment->purifyHtml($dirtyHTML)
1004
        );
1005
    }
1006
1007
    public function testGravatar()
1008
    {
1009
        // Turn gravatars on
1010
        Config::inst()->update(CommentableItem::class, 'comments', array(
1011
            'use_gravatar' => true
1012
        ));
1013
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1014
1015
        $this->assertEquals(
1016
            'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
1017
            . '=80&d=identicon&r=g',
1018
            $comment->gravatar()
1019
        );
1020
1021
        // Turn gravatars off
1022
        Config::inst()->update(CommentableItem::class, 'comments', array(
1023
            'use_gravatar' => false
1024
        ));
1025
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1026
1027
        $this->assertEquals(
1028
            '',
1029
            $comment->gravatar()
1030
        );
1031
    }
1032
1033
    public function testGetRepliesEnabled()
1034
    {
1035
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1036
        Config::inst()->update(CommentableItem::class, 'comments', array(
1037
            'nested_comments' => false
1038
        ));
1039
        $this->assertFalse($comment->getRepliesEnabled());
1040
1041
        Config::inst()->update(CommentableItem::class, 'comments', array(
1042
            'nested_comments' => true,
1043
            'nested_depth' => 4
1044
        ));
1045
        $this->assertTrue($comment->getRepliesEnabled());
1046
1047
        $comment->Depth = 4;
1048
        $this->assertFalse($comment->getRepliesEnabled());
1049
1050
1051
        // 0 indicates no limit for nested_depth
1052
        Config::inst()->update(CommentableItem::class, 'comments', array(
1053
            'nested_comments' => true,
1054
            'nested_depth' => 0
1055
        ));
1056
1057
        $comment->Depth = 234;
1058
        $this->assertTrue($comment->getRepliesEnabled());
1059
        $comment->markUnapproved();
1060
        $this->assertFalse($comment->getRepliesEnabled());
1061
        $comment->markSpam();
1062
        $this->assertFalse($comment->getRepliesEnabled());
1063
1064
        $comment->markApproved();
1065
        $this->assertTrue($comment->getRepliesEnabled());
1066
    }
1067
1068
    public function testAllReplies()
1069
    {
1070
        Config::inst()->update(CommentableItem::class, 'comments', array(
1071
            'nested_comments' => true,
1072
            'nested_depth' => 4
1073
        ));
1074
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1075
        $this->assertEquals(
1076
            3,
1077
            $comment->allReplies()->count()
1078
        );
1079
        $child = new Comment();
1080
        $child->Name = 'Fred Smith';
1081
        $child->Comment = 'This is a child comment';
1082
        $child->ParentCommentID = $comment->ID;
1083
1084
        // spam should be returned by this method
1085
        $child->markSpam();
1086
        $child->write();
1087
        $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...
1088
        $this->assertEquals(
1089
            4,
1090
            $comment->allReplies()->count()
1091
        );
1092
1093
        Config::inst()->update(CommentableItem::class, 'comments', array(
1094
            'nested_comments' => false
1095
        ));
1096
1097
        $this->assertEquals(0, $comment->allReplies()->count());
1098
    }
1099
1100
    public function testReplies()
1101
    {
1102
        CommentableItem::add_extension(CommentsExtension::class);
1103
        $this->logInWithPermission('ADMIN');
1104
        Config::inst()->update(CommentableItem::class, 'comments', array(
1105
            'nested_comments' => true,
1106
            'nested_depth' => 4
1107
        ));
1108
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1109
        $this->assertEquals(
1110
            3,
1111
            $comment->Replies()->count()
1112
        );
1113
1114
        // Test that spam comments are not returned
1115
        $childComment = $comment->Replies()->first();
1116
        $childComment->IsSpam = 1;
1117
        $childComment->write();
1118
        $this->assertEquals(
1119
            2,
1120
            $comment->Replies()->count()
1121
        );
1122
1123
        // Test that unmoderated comments are not returned
1124
        //
1125
        $childComment = $comment->Replies()->first();
1126
1127
        // FIXME - moderation settings scenarios need checked here
1128
        $childComment->Moderated = 0;
1129
        $childComment->IsSpam = 0;
1130
        $childComment->write();
1131
        $this->assertEquals(
1132
            2,
1133
            $comment->Replies()->count()
1134
        );
1135
1136
1137
        // Test moderation required on the front end
1138
        $item = $this->objFromFixture(CommentableItem::class, 'first');
1139
        $item->ModerationRequired = 'Required';
1140
        $item->write();
1141
1142
        Config::inst()->update(CommentableItemDisabled::class, 'comments', array(
1143
            'nested_comments' => true,
1144
            'nested_depth' => 4,
1145
            'frontend_moderation' => true
1146
        ));
1147
1148
        $comment = DataObject::get_by_id(Comment::class, $comment->ID);
1149
1150
        $this->assertEquals(
1151
            2,
1152
            $comment->Replies()->count()
1153
        );
1154
1155
        // Turn off nesting, empty array should be returned
1156
        Config::inst()->update(CommentableItem::class, 'comments', array(
1157
            'nested_comments' => false
1158
        ));
1159
1160
        $this->assertEquals(
1161
            0,
1162
            $comment->Replies()->count()
1163
        );
1164
1165
        CommentableItem::remove_extension(CommentsExtension::class);
1166
    }
1167
1168
    public function testPagedReplies()
1169
    {
1170
        Config::inst()->update(CommentableItem::class, 'comments', array(
1171
            'nested_comments' => true,
1172
            'nested_depth' => 4,
1173
            'comments_per_page' => 2 #Force 2nd page for 3 items
1174
        ));
1175
1176
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1177
        $pagedList = $comment->pagedReplies();
1178
        $this->assertEquals(
1179
            2,
1180
            $pagedList->TotalPages()
1181
        );
1182
        $this->assertEquals(
1183
            3,
1184
            $pagedList->getTotalItems()
1185
        );
1186
        //TODO - 2nd page requires controller
1187
        //
1188
        Config::inst()->update(CommentableItem::class, 'comments', array(
1189
            'nested_comments' => false
1190
        ));
1191
1192
        $this->assertEquals(0, $comment->PagedReplies()->count());
1193
    }
1194
1195
    public function testReplyForm()
1196
    {
1197
        Config::inst()->update(CommentableItem::class, 'comments', array(
1198
            'nested_comments' => false,
1199
            'nested_depth' => 4
1200
        ));
1201
1202
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1203
1204
        // No nesting, no reply form
1205
        $form = $comment->replyForm();
1206
        $this->assertNull($form);
1207
1208
        // parent item so show form
1209
        Config::inst()->update(CommentableItem::class, 'comments', array(
1210
            'nested_comments' => true,
1211
            'nested_depth' => 4
1212
        ));
1213
        $form = $comment->replyForm();
1214
1215
        $names = array();
1216
        foreach ($form->Fields() as $field) {
1217
            array_push($names, $field->getName());
1218
        }
1219
1220
        $this->assertEquals(
1221
            array(
1222
                'NameEmailURLComment', // The CompositeField name?
1223
                'ParentID',
1224
                'ParentClassName',
1225
                'ReturnURL',
1226
                'ParentCommentID'
1227
            ),
1228
            $names
1229
        );
1230
1231
        // no parent, no reply form
1232
1233
        $comment->ParentID = 0;
1234
        $comment->ParentClass = null;
1235
        $comment->write();
1236
        $form = $comment->replyForm();
1237
        $this->assertNull($form);
1238
    }
1239
1240
    public function testUpdateDepth()
1241
    {
1242
        Config::inst()->update(CommentableItem::class, 'comments', array(
1243
            'nested_comments' => true,
1244
            'nested_depth' => 4
1245
        ));
1246
1247
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1248
        $children = $comment->allReplies()->toArray();
1249
        // Make the second child a child of the first
1250
        // Make the third child a child of the second
1251
        $reply1 = $children[0];
1252
        $reply2 = $children[1];
1253
        $reply3 = $children[2];
1254
        $reply2->ParentCommentID = $reply1->ID;
1255
        $reply2->write();
1256
        $this->assertEquals(3, $reply2->Depth);
1257
        $reply3->ParentCommentID = $reply2->ID;
1258
        $reply3->write();
1259
        $this->assertEquals(4, $reply3->Depth);
1260
    }
1261
1262
    public function testGetToken()
1263
    {
1264
        $this->markTestSkipped('TODO');
1265
    }
1266
1267
    public function testMemberSalt()
1268
    {
1269
        $this->markTestSkipped('TODO');
1270
    }
1271
1272
    public function testAddToUrl()
1273
    {
1274
        $this->markTestSkipped('TODO');
1275
    }
1276
1277
    public function testCheckRequest()
1278
    {
1279
        $this->markTestSkipped('TODO');
1280
    }
1281
1282
    public function testGenerate()
1283
    {
1284
        $this->markTestSkipped('TODO');
1285
    }
1286
1287
    protected static function getMethod($name)
1288
    {
1289
        $class = new ReflectionClass(Comment::class);
1290
        $method = $class->getMethod($name);
1291
        $method->setAccessible(true);
1292
        return $method;
1293
    }
1294
}
1295