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