xref: /dokuwiki/_test/tests/Parsing/ParserMode/GfmEmphasisTest.php (revision bcefb8ae61f4ff776efdbad9508c8ee8e5c548a6)
1<?php
2
3namespace dokuwiki\test\Parsing\ParserMode;
4
5use dokuwiki\Parsing\ModeRegistry;
6use dokuwiki\Parsing\ParserMode\GfmEmphasis;
7
8/**
9 * Tests for the GFM asterisk emphasis mode (`*text*`).
10 *
11 * Mirrors the existing FormattingTest pattern: one mode loaded in isolation,
12 * assertions against handler instruction sequences.
13 *
14 * The setUp flips ModeRegistry to `markdown` syntax so that the Base mode
15 * (constructed by the Parser) recognizes `gfm_emphasis` as an allowed nested
16 * mode. Without this, Base's allowedModes would be the dokuwiki set and would
17 * silently drop our entry pattern.
18 */
19class GfmEmphasisTest extends ParserTestBase
20{
21    public function setUp(): void
22    {
23        parent::setUp();
24        global $conf;
25        $conf['syntax'] = 'markdown';
26        ModeRegistry::reset();
27    }
28
29    public function tearDown(): void
30    {
31        ModeRegistry::reset();
32        parent::tearDown();
33    }
34
35    function testBasicAsterisk()
36    {
37        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
38        $this->P->parse('Foo *Bar* Baz');
39        $calls = [
40            ['document_start', []],
41            ['p_open', []],
42            ['cdata', ["\nFoo "]],
43            ['emphasis_open', []],
44            ['cdata', ['Bar']],
45            ['emphasis_close', []],
46            ['cdata', [' Baz']],
47            ['p_close', []],
48            ['document_end', []],
49        ];
50        $this->assertCalls($calls, $this->H->calls);
51    }
52
53    function testSingleCharacter()
54    {
55        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
56        $this->P->parse('foo *b* bar');
57        $calls = [
58            ['document_start', []],
59            ['p_open', []],
60            ['cdata', ["\nfoo "]],
61            ['emphasis_open', []],
62            ['cdata', ['b']],
63            ['emphasis_close', []],
64            ['cdata', [' bar']],
65            ['p_close', []],
66            ['document_end', []],
67        ];
68        $this->assertCalls($calls, $this->H->calls);
69    }
70
71    function testMultipleWords()
72    {
73        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
74        $this->P->parse('*three four five*');
75        $calls = [
76            ['document_start', []],
77            ['p_open', []],
78            ['cdata', ["\n"]],
79            ['emphasis_open', []],
80            ['cdata', ['three four five']],
81            ['emphasis_close', []],
82            ['cdata', ['']],
83            ['p_close', []],
84            ['document_end', []],
85        ];
86        $this->assertCalls($calls, $this->H->calls);
87    }
88
89    function testTwoSeparateEmphasisOnOneLine()
90    {
91        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
92        $this->P->parse('*one* and *two*');
93        $calls = [
94            ['document_start', []],
95            ['p_open', []],
96            ['cdata', ["\n"]],
97            ['emphasis_open', []],
98            ['cdata', ['one']],
99            ['emphasis_close', []],
100            ['cdata', [' and ']],
101            ['emphasis_open', []],
102            ['cdata', ['two']],
103            ['emphasis_close', []],
104            ['cdata', ['']],
105            ['p_close', []],
106            ['document_end', []],
107        ];
108        $this->assertCalls($calls, $this->H->calls);
109    }
110
111    function testUnmatchedOpenerDoesNotEmphasise()
112    {
113        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
114        $this->P->parse('foo *bar with no closer');
115        $calls = [
116            ['document_start', []],
117            ['p_open', []],
118            ['cdata', ["\nfoo *bar with no closer"]],
119            ['p_close', []],
120            ['document_end', []],
121        ];
122        $this->assertCalls($calls, $this->H->calls);
123    }
124
125    function testOpenerFollowedBySpaceDoesNotEmphasise()
126    {
127        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
128        $this->P->parse('foo * bar* baz');
129        $calls = [
130            ['document_start', []],
131            ['p_open', []],
132            ['cdata', ["\nfoo * bar* baz"]],
133            ['p_close', []],
134            ['document_end', []],
135        ];
136        $this->assertCalls($calls, $this->H->calls);
137    }
138
139    function testEmptyDelimiterDoesNotEmphasise()
140    {
141        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
142        $this->P->parse('foo ** bar');
143        $calls = [
144            ['document_start', []],
145            ['p_open', []],
146            ['cdata', ["\nfoo ** bar"]],
147            ['p_close', []],
148            ['document_end', []],
149        ];
150        $this->assertCalls($calls, $this->H->calls);
151    }
152
153    function testUnderscoreIsNotEmphasised()
154    {
155        // GfmEmphasis handles `*` only — `_` is reserved to avoid the
156        // `__underline__` conflict. See SPEC.md.
157        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
158        $this->P->parse('foo _bar_ baz');
159        $calls = [
160            ['document_start', []],
161            ['p_open', []],
162            ['cdata', ["\nfoo _bar_ baz"]],
163            ['p_close', []],
164            ['document_end', []],
165        ];
166        $this->assertCalls($calls, $this->H->calls);
167    }
168
169    function testMultilineEmphasis()
170    {
171        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
172        $this->P->parse("*line\nline\nline*");
173        $calls = [
174            ['document_start', []],
175            ['p_open', []],
176            ['cdata', ["\n"]],
177            ['emphasis_open', []],
178            ['cdata', ["line\nline\nline"]],
179            ['emphasis_close', []],
180            ['cdata', ['']],
181            ['p_close', []],
182            ['document_end', []],
183        ];
184        $this->assertCalls($calls, $this->H->calls);
185    }
186
187    function testModeNameIsDistinctFromInstructionName()
188    {
189        // The lexer mode is registered as 'gfm_emphasis' (to avoid collision
190        // with DW Emphasis), but instructions are 'emphasis_open/close'
191        // so the existing XHTML renderer emits <em>.
192        $mode = new GfmEmphasis();
193        $this->assertSame(80, $mode->getSort());
194    }
195
196    function testDoesNotSpanParagraphBoundary()
197    {
198        // An unclosed `*` followed by a blank line must stay literal — the
199        // entry pattern's lookahead is paragraph-boundary-safe.
200        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
201        $this->P->parse("*open\n\nclose*");
202        $modes = array_column($this->H->calls, 0);
203        $this->assertNotContains('emphasis_open', $modes,
204            'GfmEmphasis must not open when the closing `*` is past a blank line');
205    }
206
207    function testAllowsSingleNewline()
208    {
209        // Single newlines are fine inside emphasis (multi-line emphasis).
210        $this->P->addMode('gfm_emphasis', new GfmEmphasis());
211        $this->P->parse("*open\nclose*");
212        $modes = array_column($this->H->calls, 0);
213        $this->assertContains('emphasis_open', $modes,
214            'GfmEmphasis must still match across a single newline');
215    }
216}
217