xref: /dokuwiki/_test/tests/Parsing/ParserMode/GfmTableTest.php (revision 74031e463764923581b9204cebc0fc3f34ce881f)
13dabe4e0SAndreas Gohr<?php
23dabe4e0SAndreas Gohr
33dabe4e0SAndreas Gohrnamespace dokuwiki\test\Parsing\ParserMode;
43dabe4e0SAndreas Gohr
53dabe4e0SAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmTable;
63dabe4e0SAndreas Gohr
73dabe4e0SAndreas Gohr/**
83dabe4e0SAndreas Gohr * Tests for GFM table blocks.
93dabe4e0SAndreas Gohr *
103dabe4e0SAndreas Gohr * GfmTable uses an entry/exit lexer state with allowedModes-driven inline
113dabe4e0SAndreas Gohr * nesting, then runs a small post-pass rewriter (Handler\GfmTable) that
123dabe4e0SAndreas Gohr * derives column alignment from the delimiter row, drops it, pads/truncates
133dabe4e0SAndreas Gohr * body rows, and emits the canonical DokuWiki table call sequence. Tests
143dabe4e0SAndreas Gohr * here assert against the rewriter's output, not the raw `gfm_table_*`
153dabe4e0SAndreas Gohr * tokens it consumes.
163dabe4e0SAndreas Gohr */
173dabe4e0SAndreas Gohrclass GfmTableTest extends ParserTestBase
183dabe4e0SAndreas Gohr{
193dabe4e0SAndreas Gohr    public function testSort()
203dabe4e0SAndreas Gohr    {
213dabe4e0SAndreas Gohr        $this->assertSame(55, (new GfmTable())->getSort());
223dabe4e0SAndreas Gohr    }
233dabe4e0SAndreas Gohr
243dabe4e0SAndreas Gohr    /** Spec example 198: basic table, no alignment, plain text. */
253dabe4e0SAndreas Gohr    public function testBasicTable()
263dabe4e0SAndreas Gohr    {
273dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
283dabe4e0SAndreas Gohr        $this->P->parse("| foo | bar |\n| --- | --- |\n| baz | bim |");
293dabe4e0SAndreas Gohr
303dabe4e0SAndreas Gohr        $expected = [
313dabe4e0SAndreas Gohr            ['document_start', []],
323dabe4e0SAndreas Gohr            ['table_open', [2, 2, 1]],
333dabe4e0SAndreas Gohr            ['tablethead_open', []],
343dabe4e0SAndreas Gohr            ['tablerow_open', []],
353dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
363dabe4e0SAndreas Gohr            ['cdata', ['foo']],
373dabe4e0SAndreas Gohr            ['tableheader_close', []],
383dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
393dabe4e0SAndreas Gohr            ['cdata', ['bar']],
403dabe4e0SAndreas Gohr            ['tableheader_close', []],
413dabe4e0SAndreas Gohr            ['tablerow_close', []],
423dabe4e0SAndreas Gohr            ['tablethead_close', []],
433dabe4e0SAndreas Gohr            ['tabletbody_open', []],
443dabe4e0SAndreas Gohr            ['tablerow_open', []],
453dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
463dabe4e0SAndreas Gohr            ['cdata', ['baz']],
473dabe4e0SAndreas Gohr            ['tablecell_close', []],
483dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
493dabe4e0SAndreas Gohr            ['cdata', ['bim']],
503dabe4e0SAndreas Gohr            ['tablecell_close', []],
513dabe4e0SAndreas Gohr            ['tablerow_close', []],
523dabe4e0SAndreas Gohr            ['tabletbody_close', []],
533dabe4e0SAndreas Gohr            ['table_close', [42]],
543dabe4e0SAndreas Gohr            ['document_end', []],
553dabe4e0SAndreas Gohr        ];
563dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
573dabe4e0SAndreas Gohr    }
583dabe4e0SAndreas Gohr
593dabe4e0SAndreas Gohr    /** Spec example 199: alignment via `:-:` and `---:`, no outer pipes. */
603dabe4e0SAndreas Gohr    public function testAlignment()
613dabe4e0SAndreas Gohr    {
623dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
633dabe4e0SAndreas Gohr        $this->P->parse("| abc | defghi |\n:-: | -----------:\nbar | baz");
643dabe4e0SAndreas Gohr
653dabe4e0SAndreas Gohr        $expected = [
663dabe4e0SAndreas Gohr            ['document_start', []],
673dabe4e0SAndreas Gohr            ['table_open', [2, 2, 1]],
683dabe4e0SAndreas Gohr            ['tablethead_open', []],
693dabe4e0SAndreas Gohr            ['tablerow_open', []],
703dabe4e0SAndreas Gohr            ['tableheader_open', [1, 'center', 1]],
713dabe4e0SAndreas Gohr            ['cdata', ['abc']],
723dabe4e0SAndreas Gohr            ['tableheader_close', []],
733dabe4e0SAndreas Gohr            ['tableheader_open', [1, 'right', 1]],
743dabe4e0SAndreas Gohr            ['cdata', ['defghi']],
753dabe4e0SAndreas Gohr            ['tableheader_close', []],
763dabe4e0SAndreas Gohr            ['tablerow_close', []],
773dabe4e0SAndreas Gohr            ['tablethead_close', []],
783dabe4e0SAndreas Gohr            ['tabletbody_open', []],
793dabe4e0SAndreas Gohr            ['tablerow_open', []],
803dabe4e0SAndreas Gohr            ['tablecell_open', [1, 'center', 1]],
813dabe4e0SAndreas Gohr            ['cdata', ['bar']],
823dabe4e0SAndreas Gohr            ['tablecell_close', []],
833dabe4e0SAndreas Gohr            ['tablecell_open', [1, 'right', 1]],
843dabe4e0SAndreas Gohr            ['cdata', ['baz']],
853dabe4e0SAndreas Gohr            ['tablecell_close', []],
863dabe4e0SAndreas Gohr            ['tablerow_close', []],
873dabe4e0SAndreas Gohr            ['tabletbody_close', []],
883dabe4e0SAndreas Gohr            ['table_close', [46]],
893dabe4e0SAndreas Gohr            ['document_end', []],
903dabe4e0SAndreas Gohr        ];
913dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
923dabe4e0SAndreas Gohr    }
933dabe4e0SAndreas Gohr
943dabe4e0SAndreas Gohr    /** Spec example 200 (partial): a backslash-escaped pipe must not split
95*74031e46SAndreas Gohr     *  the cell, and per the GFM tables extension `\|` unescapes to `|`
96*74031e46SAndreas Gohr     *  in the rendered cell — even when no general escape mode is active.
97*74031e46SAndreas Gohr     *  This test exercises GfmTable in isolation (no gfm_escape registered)
98*74031e46SAndreas Gohr     *  so the rewriter's own per-cell `\|`→`|` pass is what produces the
99*74031e46SAndreas Gohr     *  unescape. */
1003dabe4e0SAndreas Gohr    public function testEscapedPipeDoesNotSplitCell()
1013dabe4e0SAndreas Gohr    {
1023dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
1033dabe4e0SAndreas Gohr        $this->P->parse("| f\\|oo |\n| ---- |");
1043dabe4e0SAndreas Gohr
105*74031e46SAndreas Gohr        // One cell, content `f|oo`: the `\|` is unescaped by GfmTable's
106*74031e46SAndreas Gohr        // tables-extension pipe rewrite.
1073dabe4e0SAndreas Gohr        $expected = [
1083dabe4e0SAndreas Gohr            ['document_start', []],
1093dabe4e0SAndreas Gohr            ['table_open', [1, 1, 1]],
1103dabe4e0SAndreas Gohr            ['tablethead_open', []],
1113dabe4e0SAndreas Gohr            ['tablerow_open', []],
1123dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
113*74031e46SAndreas Gohr            ['cdata', ['f|oo']],
1143dabe4e0SAndreas Gohr            ['tableheader_close', []],
1153dabe4e0SAndreas Gohr            ['tablerow_close', []],
1163dabe4e0SAndreas Gohr            ['tablethead_close', []],
1173dabe4e0SAndreas Gohr            ['table_close', [19]],
1183dabe4e0SAndreas Gohr            ['document_end', []],
1193dabe4e0SAndreas Gohr        ];
1203dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
1213dabe4e0SAndreas Gohr    }
1223dabe4e0SAndreas Gohr
1233dabe4e0SAndreas Gohr    /** Spec example 201: a blockquote line terminates the table. */
1243dabe4e0SAndreas Gohr    public function testTerminatedByBlockquote()
1253dabe4e0SAndreas Gohr    {
1263dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
1273dabe4e0SAndreas Gohr        $this->P->parse("| abc | def |\n| --- | --- |\n| bar | baz |\n> bar");
1283dabe4e0SAndreas Gohr
1293dabe4e0SAndreas Gohr        // Expect the table to end at the start of `> bar`; the trailing
1303dabe4e0SAndreas Gohr        // `> bar` is left as cdata (no quote mode added in this test).
1313dabe4e0SAndreas Gohr        $expected = [
1323dabe4e0SAndreas Gohr            ['document_start', []],
1333dabe4e0SAndreas Gohr            ['table_open', [2, 2, 1]],
1343dabe4e0SAndreas Gohr            ['tablethead_open', []],
1353dabe4e0SAndreas Gohr            ['tablerow_open', []],
1363dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
1373dabe4e0SAndreas Gohr            ['cdata', ['abc']],
1383dabe4e0SAndreas Gohr            ['tableheader_close', []],
1393dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
1403dabe4e0SAndreas Gohr            ['cdata', ['def']],
1413dabe4e0SAndreas Gohr            ['tableheader_close', []],
1423dabe4e0SAndreas Gohr            ['tablerow_close', []],
1433dabe4e0SAndreas Gohr            ['tablethead_close', []],
1443dabe4e0SAndreas Gohr            ['tabletbody_open', []],
1453dabe4e0SAndreas Gohr            ['tablerow_open', []],
1463dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
1473dabe4e0SAndreas Gohr            ['cdata', ['bar']],
1483dabe4e0SAndreas Gohr            ['tablecell_close', []],
1493dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
1503dabe4e0SAndreas Gohr            ['cdata', ['baz']],
1513dabe4e0SAndreas Gohr            ['tablecell_close', []],
1523dabe4e0SAndreas Gohr            ['tablerow_close', []],
1533dabe4e0SAndreas Gohr            ['tabletbody_close', []],
1543dabe4e0SAndreas Gohr            ['table_close', [42]],
1553dabe4e0SAndreas Gohr            ['p_open', []],
1563dabe4e0SAndreas Gohr            ['cdata', ['> bar']],
1573dabe4e0SAndreas Gohr            ['p_close', []],
1583dabe4e0SAndreas Gohr            ['document_end', []],
1593dabe4e0SAndreas Gohr        ];
1603dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
1613dabe4e0SAndreas Gohr    }
1623dabe4e0SAndreas Gohr
1633dabe4e0SAndreas Gohr    /** Spec example 202: short body row gets padded to header column count. */
1643dabe4e0SAndreas Gohr    public function testShortBodyRowPadded()
1653dabe4e0SAndreas Gohr    {
1663dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
1673dabe4e0SAndreas Gohr        $this->P->parse("| abc | def |\n| --- | --- |\n| bar | baz |\nbar");
1683dabe4e0SAndreas Gohr
1693dabe4e0SAndreas Gohr        $expected = [
1703dabe4e0SAndreas Gohr            ['document_start', []],
1713dabe4e0SAndreas Gohr            ['table_open', [2, 3, 1]],
1723dabe4e0SAndreas Gohr            ['tablethead_open', []],
1733dabe4e0SAndreas Gohr            ['tablerow_open', []],
1743dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
1753dabe4e0SAndreas Gohr            ['cdata', ['abc']],
1763dabe4e0SAndreas Gohr            ['tableheader_close', []],
1773dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
1783dabe4e0SAndreas Gohr            ['cdata', ['def']],
1793dabe4e0SAndreas Gohr            ['tableheader_close', []],
1803dabe4e0SAndreas Gohr            ['tablerow_close', []],
1813dabe4e0SAndreas Gohr            ['tablethead_close', []],
1823dabe4e0SAndreas Gohr            ['tabletbody_open', []],
1833dabe4e0SAndreas Gohr            ['tablerow_open', []],
1843dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
1853dabe4e0SAndreas Gohr            ['cdata', ['bar']],
1863dabe4e0SAndreas Gohr            ['tablecell_close', []],
1873dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
1883dabe4e0SAndreas Gohr            ['cdata', ['baz']],
1893dabe4e0SAndreas Gohr            ['tablecell_close', []],
1903dabe4e0SAndreas Gohr            ['tablerow_close', []],
1913dabe4e0SAndreas Gohr            ['tablerow_open', []],
1923dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
1933dabe4e0SAndreas Gohr            ['cdata', ['bar']],
1943dabe4e0SAndreas Gohr            ['tablecell_close', []],
1953dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
1963dabe4e0SAndreas Gohr            ['tablecell_close', []],
1973dabe4e0SAndreas Gohr            ['tablerow_close', []],
1983dabe4e0SAndreas Gohr            ['tabletbody_close', []],
1993dabe4e0SAndreas Gohr            ['table_close', [46]],
2003dabe4e0SAndreas Gohr            ['document_end', []],
2013dabe4e0SAndreas Gohr        ];
2023dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
2033dabe4e0SAndreas Gohr    }
2043dabe4e0SAndreas Gohr
2053dabe4e0SAndreas Gohr    /** Spec example 204: long body row truncated to header column count. */
2063dabe4e0SAndreas Gohr    public function testLongBodyRowTruncated()
2073dabe4e0SAndreas Gohr    {
2083dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
2093dabe4e0SAndreas Gohr        $this->P->parse("| abc | def |\n| --- | --- |\n| bar |\n| bar | baz | boo |");
2103dabe4e0SAndreas Gohr
2113dabe4e0SAndreas Gohr        $expected = [
2123dabe4e0SAndreas Gohr            ['document_start', []],
2133dabe4e0SAndreas Gohr            ['table_open', [2, 3, 1]],
2143dabe4e0SAndreas Gohr            ['tablethead_open', []],
2153dabe4e0SAndreas Gohr            ['tablerow_open', []],
2163dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
2173dabe4e0SAndreas Gohr            ['cdata', ['abc']],
2183dabe4e0SAndreas Gohr            ['tableheader_close', []],
2193dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
2203dabe4e0SAndreas Gohr            ['cdata', ['def']],
2213dabe4e0SAndreas Gohr            ['tableheader_close', []],
2223dabe4e0SAndreas Gohr            ['tablerow_close', []],
2233dabe4e0SAndreas Gohr            ['tablethead_close', []],
2243dabe4e0SAndreas Gohr            ['tabletbody_open', []],
2253dabe4e0SAndreas Gohr            ['tablerow_open', []],
2263dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
2273dabe4e0SAndreas Gohr            ['cdata', ['bar']],
2283dabe4e0SAndreas Gohr            ['tablecell_close', []],
2293dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
2303dabe4e0SAndreas Gohr            ['tablecell_close', []],
2313dabe4e0SAndreas Gohr            ['tablerow_close', []],
2323dabe4e0SAndreas Gohr            ['tablerow_open', []],
2333dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
2343dabe4e0SAndreas Gohr            ['cdata', ['bar']],
2353dabe4e0SAndreas Gohr            ['tablecell_close', []],
2363dabe4e0SAndreas Gohr            ['tablecell_open', [1, null, 1]],
2373dabe4e0SAndreas Gohr            ['cdata', ['baz']],
2383dabe4e0SAndreas Gohr            ['tablecell_close', []],
2393dabe4e0SAndreas Gohr            ['tablerow_close', []],
2403dabe4e0SAndreas Gohr            ['tabletbody_close', []],
2413dabe4e0SAndreas Gohr            ['table_close', [56]],
2423dabe4e0SAndreas Gohr            ['document_end', []],
2433dabe4e0SAndreas Gohr        ];
2443dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
2453dabe4e0SAndreas Gohr    }
2463dabe4e0SAndreas Gohr
2473dabe4e0SAndreas Gohr    /** Spec example 203: header has 2 cells, delimiter has 1 - the regex
2483dabe4e0SAndreas Gohr     *  matches but the rewriter detects the mismatch and emits cdata, which
2493dabe4e0SAndreas Gohr     *  the Block rewriter wraps in a paragraph. */
2503dabe4e0SAndreas Gohr    public function testColumnCountMismatchFallback()
2513dabe4e0SAndreas Gohr    {
2523dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
2533dabe4e0SAndreas Gohr        $this->P->parse("| abc | def |\n| --- |\n| bar |");
2543dabe4e0SAndreas Gohr
2553dabe4e0SAndreas Gohr        $expected = [
2563dabe4e0SAndreas Gohr            ['document_start', []],
2573dabe4e0SAndreas Gohr            ['p_open', []],
2583dabe4e0SAndreas Gohr            ['cdata', ["| abc | def |\n| --- |\n| bar |"]],
2593dabe4e0SAndreas Gohr            ['p_close', []],
2603dabe4e0SAndreas Gohr            ['document_end', []],
2613dabe4e0SAndreas Gohr        ];
2623dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
2633dabe4e0SAndreas Gohr    }
2643dabe4e0SAndreas Gohr
2653dabe4e0SAndreas Gohr    /** Spec example 205: header + delimiter only, no body rows. */
2663dabe4e0SAndreas Gohr    public function testEmptyBody()
2673dabe4e0SAndreas Gohr    {
2683dabe4e0SAndreas Gohr        $this->P->addMode('gfm_table', new GfmTable());
2693dabe4e0SAndreas Gohr        $this->P->parse("| abc | def |\n| --- | --- |");
2703dabe4e0SAndreas Gohr
2713dabe4e0SAndreas Gohr        $expected = [
2723dabe4e0SAndreas Gohr            ['document_start', []],
2733dabe4e0SAndreas Gohr            ['table_open', [2, 1, 1]],
2743dabe4e0SAndreas Gohr            ['tablethead_open', []],
2753dabe4e0SAndreas Gohr            ['tablerow_open', []],
2763dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
2773dabe4e0SAndreas Gohr            ['cdata', ['abc']],
2783dabe4e0SAndreas Gohr            ['tableheader_close', []],
2793dabe4e0SAndreas Gohr            ['tableheader_open', [1, null, 1]],
2803dabe4e0SAndreas Gohr            ['cdata', ['def']],
2813dabe4e0SAndreas Gohr            ['tableheader_close', []],
2823dabe4e0SAndreas Gohr            ['tablerow_close', []],
2833dabe4e0SAndreas Gohr            ['tablethead_close', []],
2843dabe4e0SAndreas Gohr            ['table_close', [28]],
2853dabe4e0SAndreas Gohr            ['document_end', []],
2863dabe4e0SAndreas Gohr        ];
2873dabe4e0SAndreas Gohr        $this->assertCalls($expected, $this->H->calls);
2883dabe4e0SAndreas Gohr    }
2893dabe4e0SAndreas Gohr}
290