Files
comic-easel/tests/CharacterListTest.php
T
coraislovely-code 2fe70a3d87 Add characterization tests for the code about to be changed
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 "<b>", 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>
2026-07-25 08:36:46 -04:00

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() );
}
}