Completed
Push — master ( e42a4c...f187a0 )
by Daniel
03:17
created

tests/CommentsTest.php (15 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @package comments
5
 */
6
class CommentsTest extends FunctionalTest
7
{
8
9
    public static $fixture_file = 'comments/tests/CommentsTest.yml';
10
11
    protected $extraDataObjects = array(
12
        'CommentableItem',
13
        'CommentableItemEnabled',
14
        'CommentableItemDisabled'
15
    );
16
17 View Code Duplication
    public function setUp()
18
    {
19
        parent::setUp();
20
        Config::nest();
21
22
        // Set good default values
23
        Config::inst()->update('CommentsExtension', 'comments', array(
24
            'enabled' => true,
25
            'enabled_cms' => false,
26
            'require_login' => false,
27
            'require_login_cms' => false,
28
            'required_permission' => false,
29
            'require_moderation_nonmembers' => false,
30
            'require_moderation' => false,
31
            'require_moderation_cms' => false,
32
            'frontend_moderation' => false,
33
            'frontend_spam' => false,
34
        ));
35
36
        // Configure this dataobject
37
        Config::inst()->update('CommentableItem', 'comments', array(
38
            'enabled_cms' => true
39
        ));
40
    }
41
42
    public function tearDown()
43
    {
44
        Config::unnest();
45
        parent::tearDown();
46
    }
47
48
    public function testCommentsList()
49
    {
50
        // comments don't require moderation so unmoderated comments can be
51
        // shown but not spam posts
52
        Config::inst()->update('CommentableItem', 'comments', array(
53
            'require_moderation_nonmembers' => false,
54
            'require_moderation' => false,
55
            'require_moderation_cms' => false,
56
        ));
57
58
        $item = $this->objFromFixture('CommentableItem', 'spammed');
59
        $this->assertEquals('None', $item->ModerationRequired);
60
61
        $this->assertDOSEquals(array(
62
            array('Name' => 'Comment 1'),
63
            array('Name' => 'Comment 3')
64
        ), $item->Comments(), 'Only 2 non spam posts should be shown');
65
66
        // when moderated, only moderated, non spam posts should be shown.
67
        Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => true));
68
        $this->assertEquals('NonMembersOnly', $item->ModerationRequired);
69
70
        // Check that require_moderation overrides this option
71
        Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => true));
72
        $this->assertEquals('Required', $item->ModerationRequired);
73
74
        $this->assertDOSEquals(array(
75
            array('Name' => 'Comment 3')
76
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
77
        $this->assertEquals(1, $item->Comments()->Count());
78
79
        // require_moderation_nonmembers still filters out unmoderated comments
80
        Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => false));
81
        $this->assertEquals(1, $item->Comments()->Count());
82
83
        Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => false));
84
        $this->assertEquals(2, $item->Comments()->Count());
85
86
        // With unmoderated comments set to display in frontend
87
        Config::inst()->update('CommentableItem', 'comments', array(
88
            'require_moderation' => true,
89
            'frontend_moderation' => true
90
        ));
91
        $this->assertEquals(1, $item->Comments()->Count());
92
93
        $this->logInWithPermission('ADMIN');
94
        $this->assertEquals(2, $item->Comments()->Count());
95
96
        // With spam comments set to display in frontend
97
        Config::inst()->update('CommentableItem', 'comments', array(
98
            'require_moderation' => true,
99
            'frontend_moderation' => false,
100
            'frontend_spam' => true,
101
        ));
102
        if ($member = Member::currentUser()) {
103
            $member->logOut();
104
        }
105
        $this->assertEquals(1, $item->Comments()->Count());
106
107
        $this->logInWithPermission('ADMIN');
108
        $this->assertEquals(2, $item->Comments()->Count());
109
110
111
        // With spam and unmoderated comments set to display in frontend
112
        Config::inst()->update('CommentableItem', 'comments', array(
113
            'require_moderation' => true,
114
            'frontend_moderation' => true,
115
            'frontend_spam' => true,
116
        ));
117
        if ($member = Member::currentUser()) {
118
            $member->logOut();
119
        }
120
        $this->assertEquals(1, $item->Comments()->Count());
121
122
        $this->logInWithPermission('ADMIN');
123
        $this->assertEquals(4, $item->Comments()->Count());
124
    }
125
126
    /**
127
     * Test moderation options configured via the CMS
128
     */
129
    public function testCommentCMSModerationList()
130
    {
131
        // comments don't require moderation so unmoderated comments can be
132
        // shown but not spam posts
133
        Config::inst()->update('CommentableItem', 'comments', array(
134
            'require_moderation' => true,
135
            'require_moderation_cms' => true,
136
        ));
137
138
        $item = $this->objFromFixture('CommentableItem', 'spammed');
139
        $this->assertEquals('None', $item->ModerationRequired);
140
141
        $this->assertDOSEquals(array(
142
            array('Name' => 'Comment 1'),
143
            array('Name' => 'Comment 3')
144
        ), $item->Comments(), 'Only 2 non spam posts should be shown');
145
146
        // when moderated, only moderated, non spam posts should be shown.
147
        $item->ModerationRequired = 'NonMembersOnly';
148
        $item->write();
149
        $this->assertEquals('NonMembersOnly', $item->ModerationRequired);
150
151
        // Check that require_moderation overrides this option
152
        $item->ModerationRequired = 'Required';
153
        $item->write();
154
        $this->assertEquals('Required', $item->ModerationRequired);
155
156
        $this->assertDOSEquals(array(
157
            array('Name' => 'Comment 3')
158
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
159
        $this->assertEquals(1, $item->Comments()->Count());
160
161
        // require_moderation_nonmembers still filters out unmoderated comments
162
        $item->ModerationRequired = 'NonMembersOnly';
163
        $item->write();
164
        $this->assertEquals(1, $item->Comments()->Count());
165
166
        $item->ModerationRequired = 'None';
167
        $item->write();
168
        $this->assertEquals(2, $item->Comments()->Count());
169
    }
170
171
    public function testCanPostComment()
172
    {
173
        Config::inst()->update('CommentableItem', 'comments', array(
174
            'require_login' => false,
175
            'require_login_cms' => false,
176
            'required_permission' => false,
177
        ));
178
        $item = $this->objFromFixture('CommentableItem', 'first');
179
        $item2 = $this->objFromFixture('CommentableItem', 'second');
180
181
        // Test restriction free commenting
182
        if ($member = Member::currentUser()) {
183
            $member->logOut();
184
        }
185
        $this->assertFalse($item->CommentsRequireLogin);
186
        $this->assertTrue($item->canPostComment());
187
188
        // Test permission required to post
189
        Config::inst()->update('CommentableItem', 'comments', array(
190
            'require_login' => true,
191
            'required_permission' => 'POSTING_PERMISSION',
192
        ));
193
        $this->assertTrue($item->CommentsRequireLogin);
194
        $this->assertFalse($item->canPostComment());
195
        $this->logInWithPermission('WRONG_ONE');
196
        $this->assertFalse($item->canPostComment());
197
        $this->logInWithPermission('POSTING_PERMISSION');
198
        $this->assertTrue($item->canPostComment());
199
        $this->logInWithPermission('ADMIN');
200
        $this->assertTrue($item->canPostComment());
201
202
        // Test require login to post, but not any permissions
203
        Config::inst()->update('CommentableItem', 'comments', array(
204
            'required_permission' => false,
205
        ));
206
        $this->assertTrue($item->CommentsRequireLogin);
207
        if ($member = Member::currentUser()) {
208
            $member->logOut();
209
        }
210
        $this->assertFalse($item->canPostComment());
211
        $this->logInWithPermission('ANY_PERMISSION');
212
        $this->assertTrue($item->canPostComment());
213
214
        // Test options set via CMS
215
        Config::inst()->update('CommentableItem', 'comments', array(
216
            'require_login' => true,
217
            'require_login_cms' => true,
218
        ));
219
        $this->assertFalse($item->CommentsRequireLogin);
220
        $this->assertTrue($item2->CommentsRequireLogin);
221
        if ($member = Member::currentUser()) {
222
            $member->logOut();
223
        }
224
        $this->assertTrue($item->canPostComment());
225
        $this->assertFalse($item2->canPostComment());
226
227
        // Login grants permission to post
228
        $this->logInWithPermission('ANY_PERMISSION');
229
        $this->assertTrue($item->canPostComment());
230
        $this->assertTrue($item2->canPostComment());
231
    }
232
    public function testDeleteComment()
233
    {
234
        // Test anonymous user
235
        if ($member = Member::currentUser()) {
236
            $member->logOut();
237
        }
238
        $comment = $this->objFromFixture('Comment', 'firstComA');
239
        $commentID = $comment->ID;
240
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
241
        $delete = $this->get('CommentingController/delete/'.$comment->ID.'?ajax=1');
242
        $this->assertEquals(403, $delete->getStatusCode());
243
        $check = DataObject::get_by_id('Comment', $commentID);
244
        $this->assertTrue($check && $check->exists());
245
246
        // Test non-authenticated user
247
        $this->logInAs('visitor');
248
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
249
250
        // Test authenticated user
251
        $this->logInAs('commentadmin');
252
        $comment = $this->objFromFixture('Comment', 'firstComA');
253
        $commentID = $comment->ID;
254
        $adminComment1Link = $comment->DeleteLink();
255
        $this->assertContains('CommentingController/delete/'.$commentID.'?t=', $adminComment1Link);
256
257
        // Test that this link can't be shared / XSS exploited
258
        $this->logInAs('commentadmin2');
259
        $delete = $this->get($adminComment1Link);
260
        $this->assertEquals(400, $delete->getStatusCode());
261
        $check = DataObject::get_by_id('Comment', $commentID);
262
        $this->assertTrue($check && $check->exists());
263
264
        // Test that this other admin can delete the comment with their own link
265
        $adminComment2Link = $comment->DeleteLink();
266
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
267
        $this->autoFollowRedirection = false;
268
        $delete = $this->get($adminComment2Link);
269
        $this->assertEquals(302, $delete->getStatusCode());
270
        $check = DataObject::get_by_id('Comment', $commentID);
271
        $this->assertFalse($check && $check->exists());
272
    }
273
274 View Code Duplication
    public function testSpamComment()
275
    {
276
        // Test anonymous user
277
        if ($member = Member::currentUser()) {
278
            $member->logOut();
279
        }
280
        $comment = $this->objFromFixture('Comment', 'firstComA');
281
        $commentID = $comment->ID;
282
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
283
        $spam = $this->get('CommentingController/spam/'.$comment->ID.'?ajax=1');
284
        $this->assertEquals(403, $spam->getStatusCode());
285
        $check = DataObject::get_by_id('Comment', $commentID);
286
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
287
288
        // Test non-authenticated user
289
        $this->logInAs('visitor');
290
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
291
292
        // Test authenticated user
293
        $this->logInAs('commentadmin');
294
        $comment = $this->objFromFixture('Comment', 'firstComA');
295
        $commentID = $comment->ID;
296
        $adminComment1Link = $comment->SpamLink();
297
        $this->assertContains('CommentingController/spam/'.$commentID.'?t=', $adminComment1Link);
298
299
        // Test that this link can't be shared / XSS exploited
300
        $this->logInAs('commentadmin2');
301
        $spam = $this->get($adminComment1Link);
302
        $this->assertEquals(400, $spam->getStatusCode());
303
        $check = DataObject::get_by_id('Comment', $comment->ID);
304
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
305
306
        // Test that this other admin can spam the comment with their own link
307
        $adminComment2Link = $comment->SpamLink();
308
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
309
        $this->autoFollowRedirection = false;
310
        $spam = $this->get($adminComment2Link);
311
        $this->assertEquals(302, $spam->getStatusCode());
312
        $check = DataObject::get_by_id('Comment', $commentID);
313
        $this->assertEquals(1, $check->IsSpam);
314
315
        // Cannot re-spam spammed comment
316
        $this->assertNull($check->SpamLink());
317
    }
318
319 View Code Duplication
    public function testHamComment()
320
    {
321
        // Test anonymous user
322
        if ($member = Member::currentUser()) {
323
            $member->logOut();
324
        }
325
        $comment = $this->objFromFixture('Comment', 'secondComC');
326
        $commentID = $comment->ID;
327
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
328
        $ham = $this->get('CommentingController/ham/'.$comment->ID.'?ajax=1');
329
        $this->assertEquals(403, $ham->getStatusCode());
330
        $check = DataObject::get_by_id('Comment', $commentID);
331
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
332
333
        // Test non-authenticated user
334
        $this->logInAs('visitor');
335
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
336
337
        // Test authenticated user
338
        $this->logInAs('commentadmin');
339
        $comment = $this->objFromFixture('Comment', 'secondComC');
340
        $commentID = $comment->ID;
341
        $adminComment1Link = $comment->HamLink();
342
        $this->assertContains('CommentingController/ham/'.$commentID.'?t=', $adminComment1Link);
343
344
        // Test that this link can't be shared / XSS exploited
345
        $this->logInAs('commentadmin2');
346
        $ham = $this->get($adminComment1Link);
347
        $this->assertEquals(400, $ham->getStatusCode());
348
        $check = DataObject::get_by_id('Comment', $comment->ID);
349
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
350
351
        // Test that this other admin can ham the comment with their own link
352
        $adminComment2Link = $comment->HamLink();
353
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
354
        $this->autoFollowRedirection = false;
355
        $ham = $this->get($adminComment2Link);
356
        $this->assertEquals(302, $ham->getStatusCode());
357
        $check = DataObject::get_by_id('Comment', $commentID);
358
        $this->assertEquals(0, $check->IsSpam);
359
360
        // Cannot re-ham hammed comment
361
        $this->assertNull($check->HamLink());
362
    }
363
364 View Code Duplication
    public function testApproveComment()
365
    {
366
        // Test anonymous user
367
        if ($member = Member::currentUser()) {
368
            $member->logOut();
369
        }
370
        $comment = $this->objFromFixture('Comment', 'secondComB');
371
        $commentID = $comment->ID;
372
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
373
        $approve = $this->get('CommentingController/approve/'.$comment->ID.'?ajax=1');
374
        $this->assertEquals(403, $approve->getStatusCode());
375
        $check = DataObject::get_by_id('Comment', $commentID);
376
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
377
378
        // Test non-authenticated user
379
        $this->logInAs('visitor');
380
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
381
382
        // Test authenticated user
383
        $this->logInAs('commentadmin');
384
        $comment = $this->objFromFixture('Comment', 'secondComB');
385
        $commentID = $comment->ID;
386
        $adminComment1Link = $comment->ApproveLink();
387
        $this->assertContains('CommentingController/approve/'.$commentID.'?t=', $adminComment1Link);
388
389
        // Test that this link can't be shared / XSS exploited
390
        $this->logInAs('commentadmin2');
391
        $approve = $this->get($adminComment1Link);
392
        $this->assertEquals(400, $approve->getStatusCode());
393
        $check = DataObject::get_by_id('Comment', $comment->ID);
394
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
395
396
        // Test that this other admin can approve the comment with their own link
397
        $adminComment2Link = $comment->ApproveLink();
398
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
399
        $this->autoFollowRedirection = false;
400
        $approve = $this->get($adminComment2Link);
401
        $this->assertEquals(302, $approve->getStatusCode());
402
        $check = DataObject::get_by_id('Comment', $commentID);
403
        $this->assertEquals(1, $check->Moderated);
404
405
        // Cannot re-approve approved comment
406
        $this->assertNull($check->ApproveLink());
407
    }
408
409
    public function testCommenterURLWrite()
410
    {
411
        $comment = new Comment();
412
        // We only care about the CommenterURL, so only set that
413
        // Check a http and https URL. Add more test urls here as needed.
414
        $protocols = array(
415
            'Http',
416
            'Https',
417
        );
418
        $url = '://example.com';
419
420
        foreach ($protocols as $protocol) {
421
            $comment->CommenterURL = $protocol . $url;
422
            // The protocol should stay as if, assuming it is valid
423
            $comment->write();
424
            $this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol');
425
        }
426
    }
427
428
    public function testSanitizesWithAllowHtml()
429
    {
430
        if (!class_exists('HTMLPurifier')) {
431
            $this->markTestSkipped('HTMLPurifier class not found');
432
            return;
433
        }
434
435
        // Add p for paragraph
436
        // NOTE: The config method appears to append to the existing array
437
        Config::inst()->update('CommentableItem', 'comments', array(
438
            'html_allowed_elements' => array('p'),
439
        ));
440
441
        // Without HTML allowed
442
        $comment1 = new Comment();
443
        $comment1->AllowHtml = false;
444
        $comment1->BaseClass = 'CommentableItem';
445
        $comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
446
        $comment1->write();
447
        $this->assertEquals(
448
            '<p><script>alert("w00t")</script>my comment</p>',
449
            $comment1->Comment,
450
            'Does not remove HTML tags with html_allowed=false, ' .
451
            'which is correct behaviour because the HTML will be escaped'
452
        );
453
454
        // With HTML allowed
455
        $comment2 = new Comment();
456
        $comment2->AllowHtml = true;
457
        $comment2->BaseClass = 'CommentableItem';
458
        $comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
459
        $comment2->write();
460
        $this->assertEquals(
461
            '<p>my comment</p>',
462
            $comment2->Comment,
463
            'Removes HTML tags which are not on the whitelist'
464
        );
465
    }
466
467
    public function testDefaultTemplateRendersHtmlWithAllowHtml()
468
    {
469
        if (!class_exists('HTMLPurifier')) {
470
            $this->markTestSkipped('HTMLPurifier class not found');
471
        }
472
473
        Config::inst()->update('CommentableItem', 'comments', array(
474
            'html_allowed_elements' => array('p'),
475
        ));
476
477
        $item = new CommentableItem();
478
        $item->write();
479
480
        // Without HTML allowed
481
        $comment = new Comment();
482
        $comment->Comment = '<p>my comment</p>';
483
        $comment->AllowHtml = false;
484
        $comment->ParentID = $item->ID;
485
        $comment->BaseClass = 'CommentableItem';
486
        $comment->write();
487
488
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
489
        $this->assertContains(
490
            '&lt;p&gt;my comment&lt;/p&gt;',
491
            $html
492
        );
493
494
        $comment->AllowHtml = true;
495
        $comment->write();
496
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
497
        $this->assertContains(
498
            '<p>my comment</p>',
499
            $html
500
        );
501
    }
502
503
504
    /**
505
     * Tests whether comments are enabled or disabled by default
506
     */
507
    public function testDefaultEnabled()
508
    {
509
        // Ensure values are set via cms (not via config)
510
        Config::inst()->update('CommentableItem', 'comments', array(
511
            'enabled_cms' => true,
512
            'require_moderation_cms' => true,
513
            'require_login_cms' => true
514
        ));
515
516
        // With default = true
517
        $obj = new CommentableItem();
518
        $this->assertTrue((bool)$obj->getCommentsOption('enabled'), "Default setting is enabled");
519
        $this->assertTrue((bool)$obj->ProvideComments);
520
        $this->assertEquals('None', $obj->ModerationRequired);
521
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
522
523
        $obj = new CommentableItemEnabled();
524
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
The property ProvideComments does not exist on object<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...
525
        $this->assertEquals('Required', $obj->ModerationRequired);
0 ignored issues
show
The property ModerationRequired does not exist on object<CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

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

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
527
528
        $obj = new CommentableItemDisabled();
529
        $this->assertFalse((bool)$obj->ProvideComments);
0 ignored issues
show
The property ProvideComments does not exist on object<CommentableItemDisabled>. 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...
530
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
The property ModerationRequired does not exist on object<CommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
531
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
The property CommentsRequireLogin does not exist on object<CommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
532
533
        // With default = false
534
        // Because of config rules about falsey values, apply config to object directly
535
        Config::inst()->update('CommentableItem', 'comments', array(
536
            'enabled' => false,
537
            'require_login' => true,
538
            'require_moderation' => true
539
        ));
540
        $obj = new CommentableItem();
541
        $this->assertFalse((bool)$obj->getCommentsOption('enabled'), "Default setting is disabled");
542
        $this->assertFalse((bool)$obj->ProvideComments);
543
        $this->assertEquals('Required', $obj->ModerationRequired);
544
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
545
546
        $obj = new CommentableItemEnabled();
547
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
The property ProvideComments does not exist on object<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...
548
        $this->assertEquals('Required', $obj->ModerationRequired);
0 ignored issues
show
The property ModerationRequired does not exist on object<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...
549
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
The property CommentsRequireLogin does not exist on object<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...
550
551
        $obj = new CommentableItemDisabled();
552
        $this->assertFalse((bool)$obj->ProvideComments);
0 ignored issues
show
The property ProvideComments does not exist on object<CommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
553
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
The property ModerationRequired does not exist on object<CommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
554
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
The property CommentsRequireLogin does not exist on object<CommentableItemDisabled>. 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...
555
    }
556
557
    /*
558
    When a parent comment is deleted, remove the children
559
     */
560
    public function testOnBeforeDelete()
561
    {
562
        $comment = $this->objFromFixture('Comment', 'firstComA');
563
564
        $child = new Comment();
565
        $child->Name = 'Fred Bloggs';
566
        $child->Comment = 'Child of firstComA';
567
        $child->write();
568
        $comment->ChildComments()->add($child);
569
        $this->assertEquals(4, $comment->ChildComments()->count());
570
571
        $commentID = $comment->ID;
572
        $childCommentID = $child->ID;
573
574
        $comment->delete();
575
576
        // assert that the new child been deleted
577
        $this->assertFalse(DataObject::get_by_id('Comment', $commentID));
578
        $this->assertFalse(DataObject::get_by_id('Comment', $childCommentID));
579
    }
580
581
    public function testRequireDefaultRecords()
582
    {
583
        $this->markTestSkipped('TODO');
584
    }
585
586
    public function testLink()
587
    {
588
        $comment = $this->objFromFixture('Comment', 'thirdComD');
589
        $this->assertEquals('CommentableItem_Controller#comment-'.$comment->ID,
590
            $comment->Link());
591
        $this->assertEquals($comment->ID, $comment->ID);
592
593
        // An orphan comment has no link
594
        $comment->ParentID = 0;
595
        $comment->write();
596
        $this->assertEquals('', $comment->Link());
597
    }
598
599
    public function testPermalink()
600
    {
601
        $comment = $this->objFromFixture('Comment', 'thirdComD');
602
        $this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
603
    }
604
605
    /*
606
    Test field labels in 2 languages
607
     */
608
    public function testFieldLabels()
609
    {
610
        $locale = i18n::get_locale();
611
        i18n::set_locale('fr');
612
        $comment = $this->objFromFixture('Comment', 'firstComA');
613
        $labels = $comment->FieldLabels();
614
        $expected = array(
615
            'Name' => 'Nom de l\'Auteur',
616
            'Comment' => 'Commentaire',
617
            'Email' => 'Email',
618
            'URL' => 'URL',
619
            'BaseClass' => 'Base Class',
620
            'Moderated' => 'Modéré?',
621
            'IsSpam' => 'Spam?',
622
            'ParentID' => 'Parent ID',
623
            'AllowHtml' => 'Allow Html',
624
            'SecretToken' => 'Secret Token',
625
            'Depth' => 'Depth',
626
            'Author' => 'Author Member',
627
            'ParentComment' => 'Parent Comment',
628
            'ChildComments' => 'Child Comments',
629
            'ParentTitle' => 'Parent',
630
            'Created' => 'Date de publication'
631
        );
632
        i18n::set_locale($locale);
633
        $this->assertEquals($expected, $labels);
634
        $labels = $comment->FieldLabels();
635
        $expected = array(
636
            'Name' => 'Author Name',
637
            'Comment' => 'Comment',
638
            'Email' => 'Email',
639
            'URL' => 'URL',
640
            'BaseClass' => 'Base Class',
641
            'Moderated' => 'Moderated?',
642
            'IsSpam' => 'Spam?',
643
            'ParentID' => 'Parent ID',
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 posted'
652
653
        );
654
        $this->assertEquals($expected, $labels);
655
    }
656
657
    public function testGetOption()
658
    {
659
        $this->markTestSkipped('TODO');
660
    }
661
662
    public function testGetParent()
663
    {
664
        $comment = $this->objFromFixture('Comment', 'firstComA');
665
        $item = $this->objFromFixture('CommentableItem', 'first');
666
        $parent = $comment->getParent();
667
        $this->assertEquals($item, $parent);
668
    }
669
670
    public function testGetParentTitle()
671
    {
672
        $comment = $this->objFromFixture('Comment', 'firstComA');
673
        $title = $comment->getParentTitle();
674
        $this->assertEquals('First', $title);
675
676
        // Title from a comment with no parent is blank
677
        $comment->ParentID = 0;
678
        $comment->write();
679
        $this->assertEquals('', $comment->getParentTitle());
680
    }
681
682
    public function testGetParentClassName()
683
    {
684
        $comment = $this->objFromFixture('Comment', 'firstComA');
685
        $className = $comment->getParentClassName();
686
        $this->assertEquals('CommentableItem', $className);
687
    }
688
689
    public function testCastingHelper()
690
    {
691
        $this->markTestSkipped('TODO');
692
    }
693
694
    public function testGetEscapedComment()
695
    {
696
        $this->markTestSkipped('TODO');
697
    }
698
699
    public function testIsPreview()
700
    {
701
        $comment = new Comment();
702
        $comment->Name = 'Fred Bloggs';
703
        $comment->Comment = 'this is a test comment';
704
        $this->assertTrue($comment->isPreview());
705
        $comment->write();
706
        $this->assertFalse($comment->isPreview());
707
    }
708
709
    public function testCanCreate()
710
    {
711
        $comment = $this->objFromFixture('Comment', 'firstComA');
712
713
        // admin can create - this is always false
714
        $this->logInAs('commentadmin');
715
        $this->assertFalse($comment->canCreate());
716
717
        // visitor can view
718
        $this->logInAs('visitor');
719
        $this->assertFalse($comment->canCreate());
720
    }
721
722 View Code Duplication
    public function testCanView()
723
    {
724
        $comment = $this->objFromFixture('Comment', 'firstComA');
725
726
        // admin can view
727
        $this->logInAs('commentadmin');
728
        $this->assertTrue($comment->canView());
729
730
        // visitor can view
731
        $this->logInAs('visitor');
732
        $this->assertTrue($comment->canView());
733
734
        $comment->ParentID = 0;
735
        $comment->write();
736
        $this->assertFalse($comment->canView());
737
    }
738
739 View Code Duplication
    public function testCanEdit()
740
    {
741
        $comment = $this->objFromFixture('Comment', 'firstComA');
742
743
        // admin can edit
744
        $this->logInAs('commentadmin');
745
        $this->assertTrue($comment->canEdit());
746
747
        // visitor cannot
748
        $this->logInAs('visitor');
749
        $this->assertFalse($comment->canEdit());
750
751
        $comment->ParentID = 0;
752
        $comment->write();
753
        $this->assertFalse($comment->canEdit());
754
    }
755
756 View Code Duplication
    public function testCanDelete()
757
    {
758
        $comment = $this->objFromFixture('Comment', 'firstComA');
759
760
        // admin can delete
761
        $this->logInAs('commentadmin');
762
        $this->assertTrue($comment->canDelete());
763
764
        // visitor cannot
765
        $this->logInAs('visitor');
766
        $this->assertFalse($comment->canDelete());
767
768
        $comment->ParentID = 0;
769
        $comment->write();
770
        $this->assertFalse($comment->canDelete());
771
    }
772
773
    public function testGetMember()
774
    {
775
        $this->logInAs('visitor');
776
        $current = Member::currentUser();
777
        $comment = $this->objFromFixture('Comment', 'firstComA');
778
        $method = $this->getMethod('getMember');
779
780
        // null case
781
        $member = $method->invokeArgs($comment, array());
782
        $this->assertEquals($current, $member);
783
784
        // numeric ID case
785
        $member = $method->invokeArgs($comment, array($current->ID));
786
        $this->assertEquals($current, $member);
787
788
        // identity case
789
        $member = $method->invokeArgs($comment, array($current));
790
        $this->assertEquals($current, $member);
791
    }
792
793
    public function testGetAuthorName()
794
    {
795
        $comment = $this->objFromFixture('Comment', 'firstComA');
796
        $this->assertEquals(
797
            'FA',
798
            $comment->getAuthorName()
799
        );
800
801
        $comment->Name = '';
802
        $this->assertEquals(
803
            '',
804
            $comment->getAuthorName()
805
        );
806
807
        $author = $this->objFromFixture('Member', 'visitor');
808
        $comment->AuthorID = $author->ID;
809
        $comment->write();
810
        $this->assertEquals(
811
            'visitor',
812
            $comment->getAuthorName()
813
        );
814
815
        // null the names, expect null back
816
        $comment->Name = null;
817
        $comment->AuthorID = 0;
818
        $this->assertNull($comment->getAuthorName());
819
    }
820
821
822
    public function testLinks()
823
    {
824
        $comment = $this->objFromFixture('Comment', 'firstComA');
825
        $this->logInAs('commentadmin');
826
827
        $method = $this->getMethod('ActionLink');
828
829
        // test with starts of strings and tokens and salts change each time
830
        $this->assertStringStartsWith(
831
            '/CommentingController/theaction/'.$comment->ID,
832
            $method->invokeArgs($comment, array('theaction'))
833
        );
834
835
        $this->assertStringStartsWith(
836
            '/CommentingController/delete/'.$comment->ID,
837
            $comment->DeleteLink()
838
        );
839
840
        $this->assertStringStartsWith(
841
            '/CommentingController/spam/'.$comment->ID,
842
            $comment->SpamLink()
843
        );
844
845
        $comment->markSpam();
846
        $this->assertStringStartsWith(
847
            '/CommentingController/ham/'.$comment->ID,
848
            $comment->HamLink()
849
        );
850
851
        //markApproved
852
        $comment->markUnapproved();
853
        $this->assertStringStartsWith(
854
            '/CommentingController/approve/'.$comment->ID,
855
            $comment->ApproveLink()
856
        );
857
    }
858
859
    public function testMarkSpam()
860
    {
861
        $comment = $this->objFromFixture('Comment', 'firstComA');
862
        $comment->markSpam();
863
        $this->assertTrue($comment->Moderated);
864
        $this->assertTrue($comment->IsSpam);
865
    }
866
867
    public function testMarkApproved()
868
    {
869
        $comment = $this->objFromFixture('Comment', 'firstComA');
870
        $comment->markApproved();
871
        $this->assertTrue($comment->Moderated);
872
        $this->assertFalse($comment->IsSpam);
873
    }
874
875
    public function testMarkUnapproved()
876
    {
877
        $comment = $this->objFromFixture('Comment', 'firstComA');
878
        $comment->markApproved();
879
        $this->assertTrue($comment->Moderated);
880
    }
881
882
    public function testSpamClass()
883
    {
884
        $comment = $this->objFromFixture('Comment', 'firstComA');
885
        $this->assertEquals('notspam', $comment->spamClass());
886
        $comment->Moderated = false;
887
        $this->assertEquals('unmoderated', $comment->spamClass());
888
        $comment->IsSpam = true;
889
        $this->assertEquals('spam', $comment->spamClass());
890
    }
891
892
    public function testGetTitle()
893
    {
894
        $comment = $this->objFromFixture('Comment', 'firstComA');
895
        $this->assertEquals(
896
            'Comment by FA on First',
897
            $comment->getTitle()
898
        );
899
    }
900
901
    public function testGetCMSFields()
902
    {
903
        $comment = $this->objFromFixture('Comment', 'firstComA');
904
        $fields = $comment->getCMSFields();
905
        $names = array();
906
        foreach ($fields as $field) {
907
            $names[] = $field->getName();
908
        }
909
        $expected = array(
910
            'Created',
911
            'Name',
912
            'Comment',
913
            'Email',
914
            'URL',
915
            null #FIXME this is suspicious
916
        );
917
        $this->assertEquals($expected, $names);
918
    }
919
920
    public function testGetCMSFieldsCommentHasAuthor()
921
    {
922
        $member = Member::get()->filter('FirstName', 'visitor')->first();
923
        $comment = $this->objFromFixture('Comment', 'firstComA');
924
        $comment->AuthorID = $member->ID;
925
        $comment->write();
926
927
        $fields = $comment->getCMSFields();
928
        $names = array();
929
        foreach ($fields as $field) {
930
            $names[] = $field->getName();
931
        }
932
        $expected = array(
933
            'Created',
934
            'Name',
935
            'AuthorMember',
936
            'Comment',
937
            'Email',
938
            'URL',
939
            null #FIXME this is suspicious
940
        );
941
        $this->assertEquals($expected, $names);
942
    }
943
944
    public function testGetCMSFieldsWithParentComment()
945
    {
946
        $comment = $this->objFromFixture('Comment', 'firstComA');
947
948
        $child = new Comment();
949
        $child->Name = 'John Smith';
950
        $child->Comment = 'This is yet another test commnent';
951
        $child->ParentCommentID = $comment->ID;
952
        $child->write();
953
954
        $fields = $child->getCMSFields();
955
        $names = array();
956
        foreach ($fields as $field) {
957
            $names[] = $field->getName();
958
        }
959
        $expected = array(
960
            'Created',
961
            'Name',
962
            'Comment',
963
            'Email',
964
            'URL',
965
            null, #FIXME this is suspicious
966
            'ParentComment_Title',
967
            'ParentComment_Created',
968
            'ParentComment_AuthorName',
969
            'ParentComment_EscapedComment'
970
        );
971
        $this->assertEquals($expected, $names);
972
    }
973
974
975
    public function testPurifyHtml()
976
    {
977
        $comment = $this->objFromFixture('Comment', 'firstComA');
978
979
        $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
980
        $this->assertEquals(
981
            'my comment',
982
            $comment->purifyHtml($dirtyHTML)
983
        );
984
    }
985
986
    public function testGravatar()
987
    {
988
        // Turn gravatars on
989
        Config::inst()->update('CommentableItem', 'comments', array(
990
            'use_gravatar' => true
991
        ));
992
        $comment = $this->objFromFixture('Comment', 'firstComA');
993
994
        $this->assertEquals(
995
            'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'.
996
            '=80&d=identicon&r=g',
997
            $comment->gravatar()
998
        );
999
1000
        // Turn gravatars off
1001
        Config::inst()->update('CommentableItem', 'comments', array(
1002
            'use_gravatar' => false
1003
        ));
1004
        $comment = $this->objFromFixture('Comment', 'firstComA');
1005
1006
        $this->assertEquals(
1007
            '',
1008
            $comment->gravatar()
1009
        );
1010
    }
1011
1012
    public function testGetRepliesEnabled()
1013
    {
1014
        $comment = $this->objFromFixture('Comment', 'firstComA');
1015
        Config::inst()->update('CommentableItem', 'comments', array(
1016
            'nested_comments' => false
1017
        ));
1018
        $this->assertFalse($comment->getRepliesEnabled());
1019
1020
        Config::inst()->update('CommentableItem', 'comments', array(
1021
            'nested_comments' => true,
1022
            'nested_depth' => 4
1023
        ));
1024
        $this->assertTrue($comment->getRepliesEnabled());
1025
1026
        $comment->Depth = 4;
1027
        $this->assertFalse($comment->getRepliesEnabled());
1028
1029
1030
        // 0 indicates no limit for nested_depth
1031
        Config::inst()->update('CommentableItem', 'comments', array(
1032
            'nested_comments' => true,
1033
            'nested_depth' => 0
1034
        ));
1035
1036
        $comment->Depth = 234;
1037
        $this->assertTrue($comment->getRepliesEnabled());
1038
        $comment->markUnapproved();
1039
        $this->assertFalse($comment->getRepliesEnabled());
1040
        $comment->markSpam();
1041
        $this->assertFalse($comment->getRepliesEnabled());
1042
1043
        $comment->markApproved();
1044
        $this->assertTrue($comment->getRepliesEnabled());
1045
    }
1046
1047
    public function testAllReplies()
1048
    {
1049
        Config::inst()->update('CommentableItem', 'comments', array(
1050
            'nested_comments' => true,
1051
            'nested_depth' => 4
1052
        ));
1053
        $comment = $this->objFromFixture('Comment', 'firstComA');
1054
        $this->assertEquals(
1055
            3,
1056
            $comment->allReplies()->count()
1057
        );
1058
        $child = new Comment();
1059
        $child->Name = 'Fred Smith';
1060
        $child->Comment = 'This is a child comment';
1061
        $child->ParentCommentID = $comment->ID;
1062
1063
        // spam should be returned by this method
1064
        $child->markSpam();
1065
        $child->write();
1066
        $replies = $comment->allReplies();
1067
        $this->assertEquals(
1068
            4,
1069
            $comment->allReplies()->count()
1070
        );
1071
1072
        Config::inst()->update('CommentableItem', 'comments', array(
1073
            'nested_comments' => false
1074
        ));
1075
1076
        $this->assertEquals(0, $comment->allReplies()->count());
1077
    }
1078
1079
    public function testReplies()
1080
    {
1081
        CommentableItem::add_extension('CommentsExtension');
1082
        $this->logInWithPermission('ADMIN');
1083
        Config::inst()->update('CommentableItem', 'comments', array(
1084
            'nested_comments' => true,
1085
            'nested_depth' => 4
1086
        ));
1087
        $comment = $this->objFromFixture('Comment', 'firstComA');
1088
        $this->assertEquals(
1089
            3,
1090
            $comment->Replies()->count()
1091
        );
1092
1093
        // Test that spam comments are not returned
1094
        $childComment = $comment->Replies()->first();
1095
        $childComment->IsSpam = 1;
1096
        $childComment->write();
1097
        $this->assertEquals(
1098
            2,
1099
            $comment->Replies()->count()
1100
        );
1101
1102
        // Test that unmoderated comments are not returned
1103
        //
1104
        $childComment = $comment->Replies()->first();
1105
1106
        // FIXME - moderation settings scenarios need checked here
1107
        $childComment->Moderated = 0;
1108
        $childComment->IsSpam = 0;
1109
        $childComment->write();
1110
        $this->assertEquals(
1111
            2,
1112
            $comment->Replies()->count()
1113
        );
1114
1115
1116
        // Test moderation required on the front end
1117
        $item = $this->objFromFixture('CommentableItem', 'first');
1118
        $item->ModerationRequired = 'Required';
1119
        $item->write();
1120
1121
        Config::inst()->update('CommentableItemDisabled', 'comments', array(
1122
            'nested_comments' => true,
1123
            'nested_depth' => 4,
1124
            'frontend_moderation' => true
1125
        ));
1126
1127
        $comment = DataObject::get_by_id('Comment', $comment->ID);
1128
1129
        $this->assertEquals(
1130
            2,
1131
            $comment->Replies()->count()
1132
        );
1133
1134
        // Turn off nesting, empty array should be returned
1135
        Config::inst()->update('CommentableItem', 'comments', array(
1136
            'nested_comments' => false
1137
        ));
1138
1139
        $this->assertEquals(
1140
            0,
1141
            $comment->Replies()->count()
1142
        );
1143
1144
        CommentableItem::remove_extension('CommentsExtension');
1145
    }
1146
1147
    public function testPagedReplies()
1148
    {
1149
        Config::inst()->update('CommentableItem', 'comments', array(
1150
            'nested_comments' => true,
1151
            'nested_depth' => 4,
1152
            'comments_per_page' => 2 #Force 2nd page for 3 items
1153
        ));
1154
1155
        $comment = $this->objFromFixture('Comment', 'firstComA');
1156
        $pagedList = $comment->pagedReplies();
1157
        $this->assertEquals(
1158
            2,
1159
            $pagedList->TotalPages()
1160
        );
1161
        $this->assertEquals(
1162
            3,
1163
            $pagedList->getTotalItems()
1164
        );
1165
        //TODO - 2nd page requires controller
1166
        //
1167
         Config::inst()->update('CommentableItem', 'comments', array(
1168
            'nested_comments' => false
1169
        ));
1170
1171
        $this->assertEquals(0, $comment->PagedReplies()->count());
1172
    }
1173
1174
    public function testReplyForm()
1175
    {
1176
        Config::inst()->update('CommentableItem', 'comments', array(
1177
            'nested_comments' => false,
1178
            'nested_depth' => 4
1179
        ));
1180
1181
        $comment = $this->objFromFixture('Comment', 'firstComA');
1182
1183
        // No nesting, no reply form
1184
        $form = $comment->replyForm();
1185
        $this->assertNull($form);
1186
1187
        // parent item so show form
1188
        Config::inst()->update('CommentableItem', 'comments', array(
1189
            'nested_comments' => true,
1190
            'nested_depth' => 4
1191
        ));
1192
        $form = $comment->replyForm();
1193
1194
        $names = array();
1195
        foreach ($form->Fields() as $field) {
1196
            array_push($names, $field->getName());
1197
        }
1198
1199
        $this->assertEquals(
1200
            array(
1201
                null, #FIXME suspicious
1202
                'ParentID',
1203
                'ReturnURL',
1204
                'ParentCommentID',
1205
                'BaseClass'
1206
            ),
1207
            $names
1208
        );
1209
1210
        // no parent, no reply form
1211
1212
        $comment->ParentID = 0;
1213
        $comment->write();
1214
        $form = $comment->replyForm();
1215
        $this->assertNull($form);
1216
    }
1217
1218
    public function testUpdateDepth()
1219
    {
1220
        Config::inst()->update('CommentableItem', 'comments', array(
1221
            'nested_comments' => true,
1222
            'nested_depth' => 4
1223
        ));
1224
1225
        $comment = $this->objFromFixture('Comment', 'firstComA');
1226
        $children = $comment->allReplies()->toArray();
1227
        // Make the second child a child of the first
1228
        // Make the third child a child of the second
1229
        $reply1 = $children[0];
1230
        $reply2 = $children[1];
1231
        $reply3 = $children[2];
1232
        $reply2->ParentCommentID = $reply1->ID;
1233
        $reply2->write();
1234
        $this->assertEquals(3, $reply2->Depth);
1235
        $reply3->ParentCommentID = $reply2->ID;
1236
        $reply3->write();
1237
        $this->assertEquals(4, $reply3->Depth);
1238
    }
1239
1240
    public function testGetToken()
1241
    {
1242
        $this->markTestSkipped('TODO');
1243
    }
1244
1245
    public function testMemberSalt()
1246
    {
1247
        $this->markTestSkipped('TODO');
1248
    }
1249
1250
    public function testAddToUrl()
1251
    {
1252
        $this->markTestSkipped('TODO');
1253
    }
1254
1255
    public function testCheckRequest()
1256
    {
1257
        $this->markTestSkipped('TODO');
1258
    }
1259
1260
    public function testGenerate()
1261
    {
1262
        $this->markTestSkipped('TODO');
1263
    }
1264
1265
1266
    protected static function getMethod($name)
1267
    {
1268
        $class = new ReflectionClass('Comment');
1269
        $method = $class->getMethod($name);
1270
        $method->setAccessible(true);
1271
        return $method;
1272
    }
1273
}
1274
1275
1276
/**
1277
 * @package comments
1278
 * @subpackage tests
1279
 */
1280
class CommentableItem extends DataObject implements TestOnly
1281
{
1282
1283
    private static $db = array(
1284
        'Title' => 'Varchar'
1285
    );
1286
1287
    private static $extensions = array(
1288
        'CommentsExtension'
1289
    );
1290
1291
    public function RelativeLink()
1292
    {
1293
        return "CommentableItem_Controller";
1294
    }
1295
1296
    public function canView($member = null)
1297
    {
1298
        return true;
1299
    }
1300
1301
    // This is needed for canModerateComments
1302
    public function canEdit($member = null)
1303
    {
1304
        if ($member instanceof Member) {
1305
            $memberID = $member->ID;
1306
        } elseif (is_numeric($member)) {
1307
            $memberID = $member;
1308
        } else {
1309
            $memberID = Member::currentUserID();
1310
        }
1311
1312
        if ($memberID && Permission::checkMember($memberID, array("ADMIN", "CMS_ACCESS_CommentAdmin"))) {
0 ignored issues
show
This if statement, and the following return statement can be replaced with return $memberID && \Per...ACCESS_CommentAdmin'));.
Loading history...
1313
            return true;
1314
        }
1315
        return false;
1316
    }
1317
1318
    public function Link()
1319
    {
1320
        return $this->RelativeLink();
1321
    }
1322
1323
    public function AbsoluteLink()
1324
    {
1325
        return Director::absoluteURL($this->RelativeLink());
1326
    }
1327
}
1328
1329 View Code Duplication
class CommentableItemEnabled extends CommentableItem
1330
{
1331
    private static $defaults = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1332
        'ProvideComments' => true,
1333
        'ModerationRequired' => 'Required',
1334
        'CommentsRequireLogin' => true
1335
    );
1336
}
1337
1338
1339 View Code Duplication
class CommentableItemDisabled extends CommentableItem
1340
{
1341
    private static $defaults = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1342
        'ProvideComments' => false,
1343
        'ModerationRequired' => 'None',
1344
        'CommentsRequireLogin' => false
1345
    );
1346
}
1347
1348
/**
1349
 * @package comments
1350
 * @subpackage tests
1351
 */
1352
class CommentableItem_Controller extends Controller implements TestOnly
1353
{
1354
1355
    public function index()
1356
    {
1357
        return CommentableItem::get()->first()->CommentsForm();
1358
    }
1359
}
1360