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

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