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