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