xref: /dokuwiki/_test/tests/Parsing/ParserMode/GfmStrongUnderscoreTest.php (revision bcefb8ae61f4ff776efdbad9508c8ee8e5c548a6)
1<?php
2
3namespace dokuwiki\test\Parsing\ParserMode;
4
5use dokuwiki\Parsing\ModeRegistry;
6use dokuwiki\Parsing\ParserMode\GfmStrongUnderscore;
7
8/**
9 * Tests for GFM strong emphasis via double underscores (`__text__`).
10 *
11 * Only loaded when Markdown is the only or preferred syntax. Combines:
12 *   - intraword word-boundary rule (multibyte-safe)
13 *   - flanking-whitespace rule (no leading/trailing space inside delimiters)
14 *   - paragraph-boundary rule (no crossing blank lines)
15 */
16class GfmStrongUnderscoreTest extends ParserTestBase
17{
18    public function setUp(): void
19    {
20        parent::setUp();
21        global $conf;
22        $conf['syntax'] = 'markdown';
23        ModeRegistry::reset();
24    }
25
26    public function tearDown(): void
27    {
28        ModeRegistry::reset();
29        parent::tearDown();
30    }
31
32    function testBasic()
33    {
34        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
35        $this->P->parse('Foo __Bar__ Baz');
36        $calls = [
37            ['document_start', []],
38            ['p_open', []],
39            ['cdata', ["\nFoo "]],
40            ['strong_open', []],
41            ['cdata', ['Bar']],
42            ['strong_close', []],
43            ['cdata', [' Baz']],
44            ['p_close', []],
45            ['document_end', []],
46        ];
47        $this->assertCalls($calls, $this->H->calls);
48    }
49
50    function testSingleCharacter()
51    {
52        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
53        $this->P->parse('__x__');
54        $modes = array_column($this->H->calls, 0);
55        $this->assertContains('strong_open', $modes);
56        $this->assertContains('strong_close', $modes);
57    }
58
59    function testMultipleWords()
60    {
61        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
62        $this->P->parse('__one two three__');
63        $modes = array_column($this->H->calls, 0);
64        $this->assertContains('strong_open', $modes);
65    }
66
67    function testIntrawordDoesNotOpen()
68    {
69        // `foo__bar__` — opening `__` intraword (preceded by `o`).
70        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
71        $this->P->parse('foo__bar__');
72        $this->assertNotContains('strong_open', array_column($this->H->calls, 0));
73    }
74
75    function testLeadingWhitespaceDoesNotOpen()
76    {
77        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
78        $this->P->parse('__ foo bar__');
79        $this->assertNotContains('strong_open', array_column($this->H->calls, 0));
80    }
81
82    function testTrailingWhitespaceDoesNotClose()
83    {
84        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
85        $this->P->parse('__foo bar __');
86        $this->assertNotContains('strong_open', array_column($this->H->calls, 0));
87    }
88
89    function testEmptyDelimiterDoesNotMatch()
90    {
91        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
92        $this->P->parse('____');
93        $this->assertNotContains('strong_open', array_column($this->H->calls, 0));
94    }
95
96    function testMultibyteIntrawordDoesNotMatch()
97    {
98        // Cyrillic spec example: `пристаням__стремятся__` — intraword, literal.
99        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
100        $this->P->parse('пристаням__стремятся__');
101        $this->assertNotContains('strong_open', array_column($this->H->calls, 0));
102    }
103
104    function testMultibyteContentInsideStrongWorks()
105    {
106        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
107        $this->P->parse('foo __für etwas__ bar');
108        $this->assertContains('strong_open', array_column($this->H->calls, 0));
109        $this->assertContains('strong_close', array_column($this->H->calls, 0));
110    }
111
112    function testDoesNotSpanParagraphBoundary()
113    {
114        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
115        $this->P->parse("__open\n\nclose__");
116        $this->assertNotContains('strong_open', array_column($this->H->calls, 0));
117    }
118
119    function testSortValue()
120    {
121        $this->assertSame(70, (new GfmStrongUnderscore())->getSort());
122    }
123
124    function testInstructionNameIsStrong()
125    {
126        // The mode name is distinct (so it coexists with DW Strong in the
127        // lexer) but it must emit the same `strong_open`/`strong_close`
128        // instructions so the XHTML renderer outputs <strong>.
129        $this->P->addMode('gfm_strong_underscore', new GfmStrongUnderscore());
130        $this->P->parse('__x__');
131        $modes = array_column($this->H->calls, 0);
132        $this->assertContains('strong_open', $modes);
133        $this->assertNotContains('gfm_strong_underscore_open', $modes);
134    }
135}
136