1*504c13e8SAndreas Gohr<?php 2*504c13e8SAndreas Gohr 3*504c13e8SAndreas Gohrnamespace dokuwiki\test\Parsing\ParserMode; 4*504c13e8SAndreas Gohr 5*504c13e8SAndreas Gohruse dokuwiki\Parsing\Handler; 6*504c13e8SAndreas Gohruse dokuwiki\Parsing\Parser; 7*504c13e8SAndreas Gohr 8*504c13e8SAndreas Gohr/** 9*504c13e8SAndreas Gohr * Base class for parser mode tests 10*504c13e8SAndreas Gohr * 11*504c13e8SAndreas Gohr * Sets up a fresh Parser and Handler for each test. Provides assertion helpers 12*504c13e8SAndreas Gohr * for comparing handler call sequences. 13*504c13e8SAndreas Gohr */ 14*504c13e8SAndreas Gohrabstract class ParserTestBase extends \DokuWikiTest 15*504c13e8SAndreas Gohr{ 16*504c13e8SAndreas Gohr /** @var Parser parser instance for the current test */ 17*504c13e8SAndreas Gohr protected Parser $P; 18*504c13e8SAndreas Gohr /** @var Handler handler instance that records calls made by the parser */ 19*504c13e8SAndreas Gohr protected Handler $H; 20*504c13e8SAndreas Gohr 21*504c13e8SAndreas Gohr /** @inheritdoc */ 22*504c13e8SAndreas Gohr public function setUp(): void 23*504c13e8SAndreas Gohr { 24*504c13e8SAndreas Gohr parent::setUp(); 25*504c13e8SAndreas Gohr $this->H = new Handler(); 26*504c13e8SAndreas Gohr $this->P = new Parser($this->H); 27*504c13e8SAndreas Gohr } 28*504c13e8SAndreas Gohr 29*504c13e8SAndreas Gohr /** @inheritdoc */ 30*504c13e8SAndreas Gohr public function tearDown(): void 31*504c13e8SAndreas Gohr { 32*504c13e8SAndreas Gohr unset($this->P, $this->H); 33*504c13e8SAndreas Gohr parent::tearDown(); 34*504c13e8SAndreas Gohr } 35*504c13e8SAndreas Gohr 36*504c13e8SAndreas Gohr /** 37*504c13e8SAndreas Gohr * Assert that handler calls match the expected calls, ignoring byte index positions 38*504c13e8SAndreas Gohr * 39*504c13e8SAndreas Gohr * The byte index (element [2] in each call) is stripped before comparison because 40*504c13e8SAndreas Gohr * it depends on internal parser state and is not relevant for most tests. 41*504c13e8SAndreas Gohr * 42*504c13e8SAndreas Gohr * @param array $expected the expected call sequence 43*504c13e8SAndreas Gohr * @param array $actual the actual handler calls (typically $this->H->calls) 44*504c13e8SAndreas Gohr * @param string $message optional failure message 45*504c13e8SAndreas Gohr */ 46*504c13e8SAndreas Gohr protected function assertCalls(array $expected, array $actual, string $message = ''): void 47*504c13e8SAndreas Gohr { 48*504c13e8SAndreas Gohr $this->assertEquals($expected, array_map($this->stripByteIndex(...), $actual), $message); 49*504c13e8SAndreas Gohr } 50*504c13e8SAndreas Gohr 51*504c13e8SAndreas Gohr /** 52*504c13e8SAndreas Gohr * Remove the byte index from a single handler call 53*504c13e8SAndreas Gohr * 54*504c13e8SAndreas Gohr * Recursively processes nested calls (e.g. footnotes). 55*504c13e8SAndreas Gohr * 56*504c13e8SAndreas Gohr * @param array $call a single handler call [method, args, byteindex] 57*504c13e8SAndreas Gohr * @return array the call with the byte index removed 58*504c13e8SAndreas Gohr */ 59*504c13e8SAndreas Gohr private function stripByteIndex(array $call): array 60*504c13e8SAndreas Gohr { 61*504c13e8SAndreas Gohr unset($call[2]); 62*504c13e8SAndreas Gohr if ($call[0] === 'nest') { 63*504c13e8SAndreas Gohr $call[1][0] = array_map($this->stripByteIndex(...), $call[1][0]); 64*504c13e8SAndreas Gohr } 65*504c13e8SAndreas Gohr return $call; 66*504c13e8SAndreas Gohr } 67*504c13e8SAndreas Gohr} 68