xref: /dokuwiki/_test/tests/Parsing/ParserMode/GfmBacktickDoubleTest.php (revision 884caed926ca0aa0af6ce3f34ae3aa7317a3361a)
1<?php
2
3namespace dokuwiki\test\Parsing\ParserMode;
4
5use dokuwiki\Parsing\ParserMode\GfmBacktickDouble;
6
7/**
8 * Tests for the GFM double-backtick code-span mode.
9 *
10 * The whole point of this length is being able to embed a lone
11 * backtick in inline code — input ``foo`bar`` renders as
12 * <code>foo`bar</code>. Combined with the edge-space strip rule,
13 * the boundaries can hold backticks too: input `` `foo` ``
14 * renders as <code>`foo`</code>.
15 */
16class GfmBacktickDoubleTest extends ParserTestBase
17{
18    public function setUp(): void
19    {
20        parent::setUp();
21        $this->setSyntax('md');
22    }
23
24    function testBasicSpan()
25    {
26        $this->P->addMode('gfm_backtick_double', new GfmBacktickDouble());
27        $this->P->parse('foo ``bar`` baz');
28        $calls = [
29            ['document_start', []],
30            ['p_open', []],
31            ['cdata', ["\nfoo "]],
32            ['monospace_open', []],
33            ['unformatted', ['bar']],
34            ['monospace_close', []],
35            ['cdata', [' baz']],
36            ['p_close', []],
37            ['document_end', []],
38        ];
39        $this->assertCalls($calls, $this->H->calls);
40    }
41
42    function testAllowsInteriorSingleBacktick()
43    {
44        // GFM example 349. Input ``foo`bar`` — a lone backtick in the
45        // body cannot be a valid n=2 closer, so it stays as content.
46        $this->P->addMode('gfm_backtick_double', new GfmBacktickDouble());
47        $this->P->parse('``foo`bar``');
48        $calls = [
49            ['document_start', []],
50            ['p_open', []],
51            ['cdata', ["\n"]],
52            ['monospace_open', []],
53            ['unformatted', ['foo`bar']],
54            ['monospace_close', []],
55            ['cdata', ['']],
56            ['p_close', []],
57            ['document_end', []],
58        ];
59        $this->assertCalls($calls, $this->H->calls);
60    }
61
62    function testStripsEdgeSpaces()
63    {
64        // GFM example 339. Input `` foo ` bar `` — one leading and one
65        // trailing space stripped; the interior lone backtick stays.
66        $this->P->addMode('gfm_backtick_double', new GfmBacktickDouble());
67        $this->P->parse('`` foo ` bar ``');
68        $calls = [
69            ['document_start', []],
70            ['p_open', []],
71            ['cdata', ["\n"]],
72            ['monospace_open', []],
73            ['unformatted', ['foo ` bar']],
74            ['monospace_close', []],
75            ['cdata', ['']],
76            ['p_close', []],
77            ['document_end', []],
78        ];
79        $this->assertCalls($calls, $this->H->calls);
80    }
81
82    function testConvertsNewlinesToSpaces()
83    {
84        // GFM example 345: newlines inside a span become single spaces,
85        // then edge-space stripping applies to the normalized body.
86        $this->P->addMode('gfm_backtick_double', new GfmBacktickDouble());
87        $this->P->parse("``\nfoo\nbar  \nbaz\n``");
88        $modes = array_column($this->H->calls, 0);
89        $this->assertContains('monospace_open', $modes);
90
91        $unformatted = array_values(array_filter(
92            $this->H->calls,
93            static fn($c) => $c[0] === 'unformatted'
94        ));
95        $this->assertCount(1, $unformatted);
96        $this->assertSame('foo bar   baz', $unformatted[0][1][0]);
97    }
98
99    function testAllWhitespaceBodyIsPreserved()
100    {
101        $this->P->addMode('gfm_backtick_double', new GfmBacktickDouble());
102        $this->P->parse('a ``   `` b');
103        $calls = [
104            ['document_start', []],
105            ['p_open', []],
106            ['cdata', ["\na "]],
107            ['monospace_open', []],
108            ['unformatted', ['   ']],
109            ['monospace_close', []],
110            ['cdata', [' b']],
111            ['p_close', []],
112            ['document_end', []],
113        ];
114        $this->assertCalls($calls, $this->H->calls);
115    }
116
117    function testEmptyDelimiterDoesNotMatch()
118    {
119        // A run of four backticks — the length-boundary guards reject it
120        // as an n=2 opener followed immediately by an n=2 closer with
121        // empty body.
122        $this->P->addMode('gfm_backtick_double', new GfmBacktickDouble());
123        $this->P->parse('foo ```` bar');
124        $modes = array_column($this->H->calls, 0);
125        $this->assertNotContains('monospace_open', $modes,
126            'Run of 4 backticks must stay literal');
127    }
128
129    function testSortValue()
130    {
131        // Shares the n=1 sort — the length-boundary guards on both modes
132        // mean they never compete for the same input anyway.
133        $mode = new GfmBacktickDouble();
134        $this->assertSame(165, $mode->getSort());
135    }
136}
137