Add PHP unit tests and page tests.
Run "composer install", then "composer test".
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
namespace Xxx\Tests\Unit;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Xxx\Tests\Support\TestCase;
|
||||
|
||||
// The functions in get_data.lib.php that read and clean request values
|
||||
class RequestArgsTest extends TestCase {
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
open_db('open');
|
||||
}
|
||||
|
||||
public static function intArgs(): array {
|
||||
return array(
|
||||
'whole number' => array('7', 7),
|
||||
'spaces around' => array(' 7 ', 7),
|
||||
'negative' => array('-3', 0),
|
||||
'above the maximum' => array('500', 100),
|
||||
'zero' => array('0', 0),
|
||||
'decimal' => array('7.5', NULL),
|
||||
'trailing text' => array('7abc', NULL),
|
||||
'leading zero' => array('07', NULL),
|
||||
'plus sign' => array('+7', 7),
|
||||
'exponent' => array('1e3', NULL),
|
||||
'SQL' => array('1; DROP TABLE xxx', NULL),
|
||||
'empty' => array('', NULL),
|
||||
);
|
||||
}
|
||||
|
||||
#[DataProvider('intArgs')]
|
||||
public function testGetIntArg(string $value, ?int $expected): void {
|
||||
$this->request(array('n' => $value));
|
||||
$this->assertSame($expected, get_int_arg('n', 0, 100));
|
||||
}
|
||||
|
||||
public function testGetIntArgMissingOrNotAString(): void {
|
||||
$this->assertNull(get_int_arg('n', 0));
|
||||
$this->request(array('n' => array('1')));
|
||||
$this->assertNull(get_int_arg('n', 0));
|
||||
}
|
||||
|
||||
public function testGetIntArgHasNoMaximumByDefault(): void {
|
||||
$this->request(array('n' => '123456789'));
|
||||
$this->assertSame(123456789, get_int_arg('n', 0));
|
||||
}
|
||||
|
||||
public function testShowNumComesFromTheRequest(): void {
|
||||
$this->request(array('show' => '12'));
|
||||
$this->assertSame(12, get_show_num());
|
||||
}
|
||||
|
||||
public function testShowNumIsCappedAndAtLeastOne(): void {
|
||||
$this->request(array('show' => '100000'));
|
||||
$this->assertSame(MAX_SHOW, get_show_num());
|
||||
$this->request(array('show' => '0'));
|
||||
$this->assertSame(1, get_show_num());
|
||||
}
|
||||
|
||||
public function testShowNumFallsBackToThePageSetting(): void {
|
||||
$GLOBALS['num_stories'] = 5;
|
||||
$this->assertSame(5, get_show_num());
|
||||
$this->request(array('show' => 'many'));
|
||||
$this->assertSame(5, get_show_num());
|
||||
}
|
||||
|
||||
public function testShowNumFallsBackToOne(): void {
|
||||
$this->assertSame(1, get_show_num());
|
||||
}
|
||||
|
||||
public function testStartNum(): void {
|
||||
$this->assertSame(0, get_start_num());
|
||||
$this->request(array('start' => '15'));
|
||||
$this->assertSame(15, get_start_num());
|
||||
$this->request(array('start' => '-15'));
|
||||
$this->assertSame(0, get_start_num());
|
||||
$this->request(array('start' => '15 OR 1=1'));
|
||||
$this->assertSame(0, get_start_num());
|
||||
}
|
||||
|
||||
public static function sorts(): array {
|
||||
return array(
|
||||
array(NULL, 'date'), array('author', 'author'), array('title', 'title'), array('date', 'date'),
|
||||
array('id', 'date'), array('title; DROP TABLE xxx', 'date'), array('TITLE', 'date'),
|
||||
);
|
||||
}
|
||||
|
||||
#[DataProvider('sorts')]
|
||||
public function testSortArgAllowsOnlyKnownColumns(?string $sort, string $expected): void {
|
||||
if ($sort !== NULL)
|
||||
$this->request(array('sort' => $sort));
|
||||
$this->assertSame($expected, get_sort_arg());
|
||||
}
|
||||
|
||||
public function testSortArgIgnoresArrays(): void {
|
||||
$this->request(array('sort' => array('title')));
|
||||
$this->assertSame('date', get_sort_arg());
|
||||
}
|
||||
|
||||
public static function orders(): array {
|
||||
return array(
|
||||
'date default' => array(array(), 'desc'),
|
||||
'title default' => array(array('sort' => 'title'), 'asc'),
|
||||
'author default' => array(array('sort' => 'author'), 'asc'),
|
||||
'asc' => array(array('order' => 'asc'), 'asc'),
|
||||
'DESC' => array(array('order' => 'DESC', 'sort' => 'title'), 'DESC'),
|
||||
'injection' => array(array('order' => 'desc, (SELECT 1)'), 'desc'),
|
||||
'unknown' => array(array('order' => 'sideways', 'sort' => 'title'), 'asc'),
|
||||
'array' => array(array('order' => array('asc')), 'desc'),
|
||||
);
|
||||
}
|
||||
|
||||
#[DataProvider('orders')]
|
||||
public function testOrderAllowsOnlyAscAndDesc(array $get, string $expected): void {
|
||||
$this->request($get);
|
||||
$this->assertSame($expected, get_order());
|
||||
}
|
||||
|
||||
public function testSearchArgs(): void {
|
||||
$this->assertNull(get_search_args());
|
||||
$this->request(array('search' => "O'Brien <b>"));
|
||||
$this->assertSame("O'Brien <b>", get_search_args());
|
||||
$this->request(array('search' => array('x')));
|
||||
$this->assertNull(get_search_args());
|
||||
}
|
||||
|
||||
public function testIdMustBeNumeric(): void {
|
||||
$this->assertNull(get_id());
|
||||
$this->request(array('id' => 'abc'));
|
||||
$this->assertNull(get_id());
|
||||
$this->request(array('id' => '1 OR 1=1'));
|
||||
$this->assertNull(get_id());
|
||||
$this->request(array('id' => '42'));
|
||||
$this->assertSame('42', get_id());
|
||||
}
|
||||
|
||||
public function testIdComesFromPostToo(): void {
|
||||
$this->request(array(), array('id' => '9'));
|
||||
$this->assertSame('9', get_id());
|
||||
}
|
||||
|
||||
public function testIdKeepsAGlobalValue(): void {
|
||||
$GLOBALS['id'] = 5;
|
||||
$this->request(array('id' => '42'));
|
||||
$this->assertSame(5, get_id());
|
||||
}
|
||||
|
||||
public function testIdIgnoresArrays(): void {
|
||||
$this->request(array('id' => array('1')));
|
||||
$this->assertNull(get_id());
|
||||
}
|
||||
|
||||
public function testQueueIsOffByDefault(): void {
|
||||
$this->assertFalse(get_queue());
|
||||
}
|
||||
|
||||
public function testQueueComesFromTheRequest(): void {
|
||||
$this->request(array('queue' => '1'));
|
||||
$this->assertTrue(get_queue());
|
||||
$GLOBALS['queue'] = NULL;
|
||||
$this->request(array('queue' => '0'));
|
||||
$this->assertFalse(get_queue());
|
||||
$GLOBALS['queue'] = NULL;
|
||||
$this->request(array('queue' => 'yes'));
|
||||
$this->assertFalse(get_queue());
|
||||
$GLOBALS['queue'] = NULL;
|
||||
$this->request(array('queue' => array('1')));
|
||||
$this->assertFalse(get_queue());
|
||||
}
|
||||
|
||||
public function testQueueIsOnForSaveAndSubmit(): void {
|
||||
foreach (array('save', 'submit') as $action) {
|
||||
$GLOBALS['action'] = $action;
|
||||
$this->request(array('queue' => '0'));
|
||||
$this->assertTrue(get_queue(), $action);
|
||||
}
|
||||
}
|
||||
|
||||
public function testQueueKeepsAGlobalValue(): void {
|
||||
$GLOBALS['queue'] = TRUE;
|
||||
$this->assertTrue(get_queue());
|
||||
}
|
||||
|
||||
public static function tables(): array {
|
||||
// is_admin, queue, move, action => table
|
||||
return array(
|
||||
'visitor reads the live table' => array(FALSE, FALSE, FALSE, 'read', 'xxx'),
|
||||
'visitor cannot read the queue' => array(FALSE, TRUE, FALSE, 'read', 'xxx'),
|
||||
'editor reads the queue' => array(TRUE, TRUE, FALSE, 'read', 'queue'),
|
||||
'editor reads the live table' => array(TRUE, FALSE, FALSE, 'read', 'xxx'),
|
||||
'visitor post goes to the queue' => array(FALSE, FALSE, FALSE, 'post', 'queue'),
|
||||
'visitor save goes to the queue' => array(FALSE, FALSE, FALSE, 'save', 'queue'),
|
||||
'visitor submit goes to the queue' => array(FALSE, FALSE, FALSE, 'submit', 'queue'),
|
||||
'visitor delete only touches the queue' => array(FALSE, FALSE, TRUE, 'delete', 'queue'),
|
||||
'editor post goes live' => array(TRUE, TRUE, TRUE, 'post', 'xxx'),
|
||||
'editor save goes to the queue' => array(TRUE, FALSE, FALSE, 'save', 'queue'),
|
||||
'editor submit goes to the queue' => array(TRUE, FALSE, FALSE, 'submit', 'queue'),
|
||||
'editor moving deletes from the queue' => array(TRUE, TRUE, TRUE, 'delete', 'queue'),
|
||||
'editor deletes from the live table' => array(TRUE, FALSE, FALSE, 'delete', 'xxx'),
|
||||
'editor deletes from the queue' => array(TRUE, TRUE, FALSE, 'delete', 'queue'),
|
||||
);
|
||||
}
|
||||
|
||||
#[DataProvider('tables')]
|
||||
public function testWhichTable(bool $isAdmin, bool $queue, bool $move, string $action, string $table): void {
|
||||
$GLOBALS['is_admin'] = $isAdmin;
|
||||
$GLOBALS['queue'] = $queue;
|
||||
$this->assertSame($table, which_table($move, $action));
|
||||
}
|
||||
|
||||
public function testPostDataHasEveryField(): void {
|
||||
$this->request(array(), array('title' => 'T', 'author' => 'A', 'email' => 'e@x.org', 'story' => '<p>S</p>',
|
||||
'comments' => 'C', 'date' => '2020-01-01', 'hidden' => 'on', 'uploaded' => 'pending',
|
||||
'editor' => 'ed', 'remove_img' => '1', 'id' => '4', 'ignored' => 'x'));
|
||||
$entry = get_post_data()[0];
|
||||
$this->assertSame(array('id', 'title', 'author', 'email', 'upload', 'story', 'comments', 'date', 'hidden',
|
||||
'uploaded', 'editor', 'remove_img', 'queue_url'), array_keys($entry));
|
||||
$this->assertSame('T', $entry['title']);
|
||||
$this->assertSame(1, $entry['remove_img']);
|
||||
$this->assertNull($entry['upload']);
|
||||
$this->assertSame(0, $entry['queue_url']);
|
||||
}
|
||||
|
||||
public function testPostDataAsStrings(): void {
|
||||
$this->request(array(), array('title' => array('not', 'a string'), 'remove_img' => '0', 'id' => '4'));
|
||||
$entry = get_post_data(TRUE)[0];
|
||||
$this->assertSame('', $entry['title']);
|
||||
$this->assertSame('', $entry['author']);
|
||||
$this->assertSame('0', $entry['remove_img']);
|
||||
$this->assertSame('4', $entry['id']);
|
||||
foreach ($entry as $value)
|
||||
$this->assertIsString($value);
|
||||
}
|
||||
|
||||
public function testPostDataEscapedForHtml(): void {
|
||||
$this->request(array(), array('title' => '<b>"T" & co</b>', 'story' => 'Wait…'));
|
||||
$entry = get_post_data(TRUE, TRUE)[0];
|
||||
$this->assertSame('<b>"T" & co</b>', $entry['title']);
|
||||
$this->assertSame('Wait…', $entry['story']);
|
||||
}
|
||||
|
||||
public function testPostDataQueueUrlFollowsTheQueue(): void {
|
||||
$GLOBALS['queue'] = TRUE;
|
||||
$this->assertSame(1, get_post_data()[0]['queue_url']);
|
||||
}
|
||||
|
||||
public function testMapHelpers(): void {
|
||||
$this->assertSame('', map_string(NULL));
|
||||
$this->assertSame('', map_string(array(1)));
|
||||
$this->assertSame('0', map_string(0));
|
||||
$this->assertSame('1', map_string(TRUE));
|
||||
$this->assertSame('<a href="x">', map_html('<a href="x">'));
|
||||
$this->assertSame('<a href="x">', unmap_html(map_html('<a href="x">')));
|
||||
$this->assertSame("it's", unmap_html('it's'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user