Such a story showed the date of the story before it, or caused a warning when it came first.
167 lines
7.3 KiB
PHP
167 lines
7.3 KiB
PHP
<?php
|
|
namespace Xxx\Tests\Unit;
|
|
|
|
use Xxx\Tests\Support\SiteData;
|
|
use Xxx\Tests\Support\TestCase;
|
|
|
|
// display_stories() in get_data.lib.php
|
|
class DisplayStoriesTest extends TestCase {
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
$GLOBALS['num_stories'] = 5;
|
|
SiteData::install(array(
|
|
'xxx' => array(
|
|
array('id' => 1, 'title' => 'First <em>title</em>', 'author' => 'Ann & "Bo"', 'date' => '2020-01-02 03:04:05',
|
|
'story' => '<p onclick="steal()">One <script>alert(1)</script>hundred</p>'),
|
|
array('id' => 2, 'title' => 'Second', 'author' => 'Cy', 'date' => '2020-01-01 10:00:00', 'story' => '<p>Two</p>'),
|
|
array('id' => 3, 'title' => 'Picture', 'author' => 'Di', 'date' => '2019-12-31 10:00:00', 'story' => '',
|
|
'img' => 'PNG', 'mime' => 'image/png', 'hidden' => '1'),
|
|
),
|
|
'queue' => array(
|
|
array('id' => 20, 'title' => 'Waiting', 'author' => 'Ed', 'date' => '2020-02-01 10:00:00'),
|
|
),
|
|
));
|
|
open_db('open');
|
|
}
|
|
|
|
public function testListsStoriesWithEscapedFields(): void {
|
|
$page = display_stories();
|
|
$this->assertStringStartsWith('<ul class="article-list">', $page);
|
|
$this->assertSame(2, substr_count($page, '<li class="box">'));
|
|
$this->assertStringContainsString('<a href="/article?id=1">First <em>title</em></a>', $page);
|
|
$this->assertStringContainsString('<dd class="author">Ann & "Bo"</dd>', $page);
|
|
$this->assertStringNotContainsString('<em>title</em>', $page);
|
|
}
|
|
|
|
public function testStoryHtmlIsPurified(): void {
|
|
$page = display_stories();
|
|
$this->assertStringContainsString('<p>One hundred</p>', $page);
|
|
$this->assertStringNotContainsString('onclick', $page);
|
|
$this->assertStringNotContainsString('alert', $page);
|
|
}
|
|
|
|
public function testDatesAreShownWithoutSecondsAndMarkedUp(): void {
|
|
$page = display_stories();
|
|
$datetime = date('Y-m-d\TH:i:sP', strtotime('2020-01-02 03:04:05'));
|
|
$this->assertStringContainsString('<time datetime="' . $datetime . '">2020-01-02 03:04</time>', $page);
|
|
}
|
|
|
|
// A story without a date shows no date, not the date of the story before it
|
|
public function testAStoryWithoutADateShowsNone(): void {
|
|
SiteData::install(array('xxx' => array(
|
|
array('id' => 1, 'title' => 'Dated', 'date' => '2020-01-02 03:04:05'),
|
|
array('id' => 2, 'title' => 'Undated', 'date' => NULL),
|
|
)));
|
|
$GLOBALS['num_stories'] = 5;
|
|
$page = display_stories();
|
|
$this->assertSame(1, substr_count($page, '<time '));
|
|
$this->assertStringContainsString('<dd class="date"></dd>', $page);
|
|
$this->assertStringContainsString('<dd class="date"></dd>', display_stories('2'));
|
|
}
|
|
|
|
public function testHiddenStoriesAreLeftOutForVisitors(): void {
|
|
$this->assertStringNotContainsString('Picture', display_stories());
|
|
}
|
|
|
|
public function testEditorsSeeHiddenStoriesMarkedAndEditLinks(): void {
|
|
$this->asEditor();
|
|
$page = display_stories();
|
|
$this->assertStringContainsString('<span class="right red">[hidden]</span>', $page);
|
|
$this->assertStringContainsString('[<a href="/publish/edit?id=3&queue=0">edit</a>]', $page);
|
|
}
|
|
|
|
public function testImagesAreServedByDisplay(): void {
|
|
$this->asEditor();
|
|
$this->assertStringContainsString('<img src="/display?id=3" alt="Picture" />', display_stories());
|
|
}
|
|
|
|
public function testEditableListLinksTitlesToTheEditor(): void {
|
|
$this->asEditor();
|
|
$GLOBALS['editable'] = TRUE;
|
|
$this->request(array('queue' => '1'));
|
|
$page = display_stories();
|
|
$this->assertStringContainsString('<a href="/publish/edit?id=20&queue=1">Waiting</a>', $page);
|
|
$this->assertStringNotContainsString('[<a href', $page);
|
|
}
|
|
|
|
public function testEditableImagesKeepTheQueue(): void {
|
|
$this->asEditor();
|
|
$GLOBALS['editable'] = TRUE;
|
|
$page = display_stories('3');
|
|
$this->assertStringContainsString('<img src="/display?id=3&queue=0" alt="Picture" />', $page);
|
|
}
|
|
|
|
public function testOneStoryHasNoPager(): void {
|
|
$page = display_stories('2');
|
|
$this->assertSame(1, substr_count($page, '<li class="box">'));
|
|
$this->assertStringNotContainsString('class="pager"', $page);
|
|
}
|
|
|
|
public function testSeveralStoriesHaveAPager(): void {
|
|
$this->assertStringContainsString('<div class="pager">', display_stories());
|
|
}
|
|
|
|
public function testNoStories(): void {
|
|
$page = display_stories('99');
|
|
$this->assertStringContainsString('<p>No articles found.</p>', $page);
|
|
$this->assertStringNotContainsString('Try searching again', $page);
|
|
}
|
|
|
|
public function testNoSearchResults(): void {
|
|
$this->request(array('search' => 'nothing like this'));
|
|
$page = display_stories();
|
|
$this->assertStringContainsString('<p>No articles found.</p>', $page);
|
|
$this->assertStringContainsString('Try searching again', $page);
|
|
}
|
|
|
|
public function testPreviewShowsThePostedStoryWithoutLinks(): void {
|
|
$GLOBALS['action'] = 'preview';
|
|
$this->request(array(), array('title' => '<b>Mine</b>', 'author' => 'Me', 'story' => '<p>My <i>story</i></p><script>x()</script>'));
|
|
$page = display_stories();
|
|
$this->assertStringContainsString('<h3 class="articletitle"><b>Mine</b></h3>', $page);
|
|
$this->assertStringContainsString('<dd class="date">Awaiting posting</dd>', $page);
|
|
$this->assertStringContainsString('<p>My <i>story</i></p>', $page);
|
|
$this->assertStringNotContainsString('x()', $page);
|
|
}
|
|
|
|
// HTML Purifier needs seconds for a few megabytes, so a posted story over the limit is not shown
|
|
public function testPreviewDoesNotShowATooLongStory(): void {
|
|
$GLOBALS['action'] = 'preview';
|
|
$this->request(array(), array('title' => 'Long', 'author' => 'Me', 'story' => '<p><b>x</b></p>' . str_repeat('a', 65536)));
|
|
$page = display_stories();
|
|
$this->assertStringContainsString('<p>The story is too long to show.</p>', $page);
|
|
$this->assertStringNotContainsString('<b>x</b>', $page);
|
|
}
|
|
|
|
public function testPreviewShowsAPendingImage(): void {
|
|
$GLOBALS['action'] = 'preview';
|
|
$GLOBALS['file_src'] = '/display?pending="><script>';
|
|
$this->request(array(), array('title' => 'Pic', 'author' => 'Me'));
|
|
$this->assertStringContainsString('<img src="/display?pending="><script>" alt="Pic" />', display_stories());
|
|
}
|
|
|
|
public function testVisitorSubmitShowsTheirStory(): void {
|
|
$GLOBALS['action'] = 'submit';
|
|
$this->request(array(), array('title' => 'Sent', 'author' => 'Me', 'story' => '<p>Done</p>'));
|
|
$page = display_stories();
|
|
$this->assertMatchesRegularExpression('/<dd class="date">Posted \d{4}-\d\d-\d\d \d\d:\d\d<\/dd>/', $page);
|
|
$this->assertStringContainsString('<h3 class="articletitle">Sent</h3>', $page);
|
|
}
|
|
|
|
public function testVisitorSeesTheImageTheySubmittedFromTheQueue(): void {
|
|
$GLOBALS['action'] = 'submit';
|
|
$_SESSION['allow_queue_image'] = '20';
|
|
$this->request(array(), array('title' => 'Sent', 'author' => 'Me', 'uploaded' => 'yes'));
|
|
$this->assertStringContainsString('<img src="/display?id=20" alt="Sent" />', display_stories());
|
|
}
|
|
|
|
// An editor's submit saves to the queue, and the page shows the saved row
|
|
public function testEditorSubmitShowsTheSavedStoryFromTheQueue(): void {
|
|
$this->asEditor();
|
|
$GLOBALS['action'] = 'submit';
|
|
$page = display_stories('20');
|
|
$this->assertStringContainsString('Waiting', $page);
|
|
$this->assertStringContainsString('<p>No articles found.</p>', display_stories('2'));
|
|
}
|
|
}
|