mirror of
https://github.com/Frumph/comic-easel.git
synced 2026-08-24 21:41:31 -04:00
2fe70a3d87
Security fixes to output escaping carry a specific risk: the fix silently changes what users see. These tests pin the behaviour that must NOT change, so that any such drift shows up as a failing assertion rather than as a bug report. Chosen deliberately to be stable across the fixes that follow, so they stay green throughout rather than needing to be rewritten by each one. The security assertions -- that a shortcode attribute cannot reach the SQL string, that a javascript: URI cannot be stored as a URL -- ship with the commits that make them true, so each fix arrives with the test that would have caught its absence. The two most valuable assertions here encode properties rather than values: - Rendering a transcript must be stable across saves: a value stored the way the save handler stores it, through esc_textarea(), must render back as exactly those bytes. The case that discriminates is an author who typed a literal entity -- esc_textarea() stores "<b>" as "&lt;b&gt;", and an escape that declines to re-encode existing entities hands back one level short, so the author's literal text decays into a live tag a save at a time. - The same round-trip property for widget link labels, fed through update() twice. ArchiveQueryTest uses the $wpdb spy rather than a database, and asserts that table names come from $wpdb rather than a hardcoded prefix -- a query with the prefix baked in silently returns nothing on any site that did not accept the installer default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
51 lines
1.7 KiB
PHP
51 lines
1.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* ceo_get_character_list() — functions/shortcodes.php
|
|
*
|
|
* Backs [cast-page chapter=N]. Takes an untrusted shortcode attribute and builds SQL from
|
|
* it, so it is worth pinning what the query is supposed to select.
|
|
*
|
|
* Note there is deliberately no assertion here that the table names come from $wpdb: on
|
|
* master this function hardcodes the default prefix, and the test for that ships with the
|
|
* commit that fixes it.
|
|
*/
|
|
class CharacterListTest extends CE_TestCase {
|
|
|
|
/** @var CE_WPDB_Spy */
|
|
private $wpdb;
|
|
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
self::loadPluginFile( 'functions/shortcodes.php' );
|
|
$this->wpdb = $this->useWpdbSpy();
|
|
}
|
|
|
|
public function testReturnsFalseWhenNoCharactersFound() {
|
|
$this->wpdb->result = array();
|
|
$this->assertFalse( ceo_get_character_list( 5 ) );
|
|
}
|
|
|
|
public function testReturnsTheRowsWhenCharactersExist() {
|
|
$row = new stdClass();
|
|
$row->tag = 'hero';
|
|
$this->wpdb->result = array( $row );
|
|
$this->assertSame( array( $row ), ceo_get_character_list( 5 ) );
|
|
}
|
|
|
|
public function testQuerySelectsCharacterNamesForPublishedComicsInAChapter() {
|
|
ceo_get_character_list( 5 );
|
|
$sql = $this->wpdb->last();
|
|
$this->assertStringContainsString( "t1.taxonomy = 'chapters'", $sql );
|
|
$this->assertStringContainsString( "t2.taxonomy = 'characters'", $sql );
|
|
$this->assertStringContainsString( "p1.post_status = 'publish'", $sql );
|
|
$this->assertStringContainsString( "p2.post_status = 'publish'", $sql );
|
|
$this->assertStringContainsString( 'p1.ID = p2.ID', $sql );
|
|
}
|
|
|
|
public function testChapterArgumentReachesTheQuery() {
|
|
ceo_get_character_list( 42 );
|
|
$this->assertStringContainsString( '42', $this->wpdb->last() );
|
|
}
|
|
}
|