examples() as $ex) { $reason = $skip[$ex['number']] ?? null; $label = sprintf('#%d %s', $ex['number'], $ex['section']); yield $label => [$ex['markdown'], $ex['html'], $reason]; } } /** * @dataProvider specProvider */ public function testExample(string $md, string $expected, ?string $skipReason): void { if ($skipReason !== null) { $this->markTestSkipped($skipReason); } $actual = $this->renderMarkdown($md); $this->assertHtmlEquals($expected, $actual); } public function tearDown(): void { ModeRegistry::reset(); parent::tearDown(); } /** * Render markdown text through DokuWiki's full parser + XHTML renderer * pipeline under the `markdown` syntax setting. */ private function renderMarkdown(string $text): string { global $conf; $conf['syntax'] = 'markdown'; ModeRegistry::reset(); $instructions = p_get_instructions($text); $info = []; return p_render('xhtml', $instructions, $info); } /** * Assert two HTML strings are equivalent after whitespace normalization. * * DokuWiki's XHTML renderer emits extra whitespace around block tags * that the spec's reference HTML omits. The comparator strips whitespace * only around **block-level** tags (p, div, h1-h6, ul/ol/li, table/tr/td, * blockquote, pre, hr). Whitespace around **inline** tags (em, strong, * a, code, span, img, br, etc.) is preserved, because `x y` * and `xy` render differently. */ private function assertHtmlEquals(string $expected, string $actual): void { $this->assertEquals( $this->normalizeHtml($expected), $this->normalizeHtml($actual) ); } /** * Strip whitespace adjacent to block-level tags; leave inline tags alone. * * Additionally drops DokuWiki-specific heading decoration that carries no * semantic meaning for GFM-conformance checks: * * - `