Files
xxx/tests/php/Pages/FeedAndImageTest.php
T
tim b68c2eb568 Give the feed of an empty site the current date.
The feed passed NULL to strtotime() when there were no stories.
2026-09-26 15:27:51 +02:00

125 lines
5.9 KiB
PHP

<?php
namespace Xxx\Tests\Pages;
use Xxx\Tests\Support\PageTestCase;
use Xxx\Tests\Support\TestCase;
// feed.php and display.php
class FeedAndImageTest extends PageTestCase {
protected function setUp(): void {
parent::setUp();
$this->setTables(array(
'xxx' => array(
array('id' => 1, 'title' => 'Tom & "Jerry"', 'author' => 'Ann <ann>', 'date' => '2021-01-03 10:00:00',
'story' => "<p>Wait&hellip; a <strong>bold</strong>\x01 move &amp; more.</p>"),
array('id' => 2, 'title' => 'Picture', 'date' => '2021-01-02 10:00:00', 'story' => '', 'img' => TestCase::png(), 'mime' => 'text/html'),
array('id' => 3, 'title' => 'Secret', 'date' => '2021-01-01 10:00:00', 'img' => TestCase::png(), 'mime' => 'image/png', 'hidden' => '1'),
array('id' => 4, 'title' => 'Not an image', 'img' => '<script>alert(1)</script>', 'mime' => 'image/png'),
),
'queue' => array(
array('id' => 9, 'title' => 'Waiting', 'img' => TestCase::png(), 'mime' => 'image/png'),
),
));
}
public function testTheFeedIsValidRss(): void {
$feed = $this->get('/feed');
$this->assertSame('application/rss+xml', $this->header($feed, 'Content-Type'));
$xml = simplexml_load_string($feed['body']);
$this->assertNotFalse($xml, $feed['body']);
$items = $xml->channel->item;
// The front page, then the visible stories, newest first
$this->assertSame(array('Front Page', 'Tom & "Jerry"', 'Picture', 'Not an image'),
array_map('strval', iterator_to_array($xml->xpath('/rss/channel/item/title'), FALSE)));
// The addresses come from SITE_URL
$this->assertSame('https://site.test/', (string)$xml->channel->link);
$this->assertSame('https://site.test/article?id=1', (string)$items[1]->link);
$this->assertSame('editor@site.test (Editors)', (string)$xml->channel->managingEditor);
$this->assertStringContainsString('&#101;&#100;&#105;', $feed['body']);
$this->assertSame('Wait… a bold move & more.', (string)$items[1]->description);
$this->assertSame('Ann <ann>', (string)$items[1]->children('http://purl.org/dc/elements/1.1/')->creator);
$this->assertSame('Image: Picture', (string)$items[2]->description);
$this->assertSame(date('D, d M Y H:i:s O', strtotime('2021-01-03 10:00:00')), (string)$xml->channel->lastBuildDate);
}
// Without stories, the feed dates are the time of the request
public function testTheFeedOfAnEmptySite(): void {
$this->setTables(array());
$xml = simplexml_load_string($this->get('/feed')['body']);
$this->assertNotFalse($xml);
$now = (string)$xml->channel->pubDate;
$this->assertSame($now, (string)$xml->channel->lastBuildDate);
$this->assertSame($now, (string)$xml->channel->item[0]->pubDate);
$this->assertCount(1, $xml->channel->item);
}
public function testAnImageIsServedWithItsRealType(): void {
$image = $this->get('/display?id=2');
$this->assertSame(200, $image['status']);
$this->assertSame(TestCase::png(), $image['body']);
$this->assertSame('image/png', $this->header($image, 'Content-Type'));
$this->assertSame('nosniff', $this->header($image, 'X-Content-Type-Options'));
$this->assertSame((string)strlen(TestCase::png()), $this->header($image, 'Content-Length'));
}
public function testDataThatIsNotAnImageIsNotServed(): void {
$image = $this->get('/display?id=4');
$this->assertSame(404, $image['status']);
$this->assertStringNotContainsString('script', $image['body']);
}
public function testAMissingImageIsNotFound(): void {
$this->assertSame(404, $this->get('/display?id=99')['status']);
$this->assertSame(404, $this->get('/display?id=1')['status']);
}
public function testHiddenImagesAreForEditorsOnly(): void {
$this->assertSame(404, $this->get('/display?id=3')['status']);
$this->loginAs();
$this->assertSame(200, $this->get('/display?id=3')['status']);
}
public function testARemovedEditorSeesNoHiddenImages(): void {
$this->loginAs();
$this->setTables(array('xxx' => $this->tables()['xxx']));
$this->assertSame(404, $this->get('/display?id=3')['status']);
}
public function testQueuedImagesNeedPermission(): void {
$this->assertSame(401, $this->get('/display?id=9&queue=1')['status']);
$this->startSession(array('allow_queue_image' => '8'));
$this->assertSame(401, $this->get('/display?id=9&queue=1')['status']);
$this->startSession(array('allow_queue_image' => '9'));
$this->assertSame(200, $this->get('/display?id=9&queue=1')['status']);
$this->loginAs();
$this->assertSame(200, $this->get('/display?id=9&queue=1')['status']);
}
public function testRestrictedImagesAreNotCached(): void {
$this->assertNull($this->header($this->get('/display?id=2'), 'Cache-Control'));
$this->loginAs();
$this->assertSame('private, no-store', $this->header($this->get('/display?id=3'), 'Cache-Control'));
$this->assertSame('private, no-store', $this->header($this->get('/display?id=9&queue=1'), 'Cache-Control'));
}
public function testThePendingUploadIsShownToItsSession(): void {
$name = bin2hex(random_bytes(16));
mkdir(self::$state . '/tmp/uploads', 0700);
file_put_contents(self::$state . "/tmp/uploads/$name", TestCase::png());
$this->assertSame(404, $this->get('/display?pending=x')['status']);
$this->startSession(array('pending_upload' => $name));
$image = $this->get('/display?pending=' . substr($name, 0, 8));
$this->assertSame(200, $image['status']);
$this->assertSame(TestCase::png(), $image['body']);
$this->assertSame('private, no-store', $this->header($image, 'Cache-Control'));
}
public function testAPendingUploadMustBeAnImage(): void {
$name = bin2hex(random_bytes(16));
mkdir(self::$state . '/tmp/uploads', 0700);
file_put_contents(self::$state . "/tmp/uploads/$name", '<html>This is not an image at all.</html>');
$this->startSession(array('pending_upload' => $name));
$this->assertSame(404, $this->get('/display?pending=x')['status']);
}
}