xref: /dokuwiki/_test/tests/Parsing/ParserMode/GfmDeletedTest.php (revision 13a62f810fbd091d15ab734b467eaec0a6bf829a)
1<?php
2
3namespace dokuwiki\test\Parsing\ParserMode;
4
5use dokuwiki\Parsing\ModeRegistry;
6use dokuwiki\Parsing\ParserMode\GfmDeleted;
7
8/**
9 * Tests for the GFM strikethrough mode (`~~text~~`).
10 */
11class GfmDeletedTest extends ParserTestBase
12{
13    public function setUp(): void
14    {
15        parent::setUp();
16        global $conf;
17        $conf['syntax'] = 'md';
18        ModeRegistry::reset();
19    }
20
21    public function tearDown(): void
22    {
23        ModeRegistry::reset();
24        parent::tearDown();
25    }
26
27    function testBasicStrikethrough()
28    {
29        $this->P->addMode('gfm_deleted', new GfmDeleted());
30        $this->P->parse('Foo ~~Bar~~ Baz');
31        $calls = [
32            ['document_start', []],
33            ['p_open', []],
34            ['cdata', ["\nFoo "]],
35            ['deleted_open', []],
36            ['cdata', ['Bar']],
37            ['deleted_close', []],
38            ['cdata', [' Baz']],
39            ['p_close', []],
40            ['document_end', []],
41        ];
42        $this->assertCalls($calls, $this->H->calls);
43    }
44
45    function testSingleCharacterBody()
46    {
47        $this->P->addMode('gfm_deleted', new GfmDeleted());
48        $this->P->parse('foo ~~b~~ bar');
49        $calls = [
50            ['document_start', []],
51            ['p_open', []],
52            ['cdata', ["\nfoo "]],
53            ['deleted_open', []],
54            ['cdata', ['b']],
55            ['deleted_close', []],
56            ['cdata', [' bar']],
57            ['p_close', []],
58            ['document_end', []],
59        ];
60        $this->assertCalls($calls, $this->H->calls);
61    }
62
63    function testMultipleWords()
64    {
65        $this->P->addMode('gfm_deleted', new GfmDeleted());
66        $this->P->parse('~~three four five~~');
67        $calls = [
68            ['document_start', []],
69            ['p_open', []],
70            ['cdata', ["\n"]],
71            ['deleted_open', []],
72            ['cdata', ['three four five']],
73            ['deleted_close', []],
74            ['cdata', ['']],
75            ['p_close', []],
76            ['document_end', []],
77        ];
78        $this->assertCalls($calls, $this->H->calls);
79    }
80
81    function testTwoSeparateStrikethroughsOnOneLine()
82    {
83        $this->P->addMode('gfm_deleted', new GfmDeleted());
84        $this->P->parse('~~one~~ and ~~two~~');
85        $calls = [
86            ['document_start', []],
87            ['p_open', []],
88            ['cdata', ["\n"]],
89            ['deleted_open', []],
90            ['cdata', ['one']],
91            ['deleted_close', []],
92            ['cdata', [' and ']],
93            ['deleted_open', []],
94            ['cdata', ['two']],
95            ['deleted_close', []],
96            ['cdata', ['']],
97            ['p_close', []],
98            ['document_end', []],
99        ];
100        $this->assertCalls($calls, $this->H->calls);
101    }
102
103    function testUnmatchedOpenerDoesNotStrike()
104    {
105        $this->P->addMode('gfm_deleted', new GfmDeleted());
106        $this->P->parse('foo ~~bar with no closer');
107        $calls = [
108            ['document_start', []],
109            ['p_open', []],
110            ['cdata', ["\nfoo ~~bar with no closer"]],
111            ['p_close', []],
112            ['document_end', []],
113        ];
114        $this->assertCalls($calls, $this->H->calls);
115    }
116
117    function testOpenerFollowedBySpaceDoesNotStrike()
118    {
119        $this->P->addMode('gfm_deleted', new GfmDeleted());
120        $this->P->parse('foo ~~ bar~~ baz');
121        $calls = [
122            ['document_start', []],
123            ['p_open', []],
124            ['cdata', ["\nfoo ~~ bar~~ baz"]],
125            ['p_close', []],
126            ['document_end', []],
127        ];
128        $this->assertCalls($calls, $this->H->calls);
129    }
130
131    function testEmptyDelimiterDoesNotStrike()
132    {
133        $this->P->addMode('gfm_deleted', new GfmDeleted());
134        $this->P->parse('foo ~~~~ bar');
135        $modes = array_column($this->H->calls, 0);
136        $this->assertNotContains('deleted_open', $modes,
137            'Empty `~~~~` must stay literal');
138    }
139
140    function testTripleTildeDoesNotStrike()
141    {
142        // `~~~` is the GFM fenced-code-block marker; strikethrough must not
143        // consume a run of three or more tildes.
144        $this->P->addMode('gfm_deleted', new GfmDeleted());
145        $this->P->parse('foo ~~~bar~~~ baz');
146        $modes = array_column($this->H->calls, 0);
147        $this->assertNotContains('deleted_open', $modes,
148            'Run of 3+ tildes must not trigger strikethrough');
149    }
150
151    function testMultilineStrikethrough()
152    {
153        $this->P->addMode('gfm_deleted', new GfmDeleted());
154        $this->P->parse("~~line\nline\nline~~");
155        $calls = [
156            ['document_start', []],
157            ['p_open', []],
158            ['cdata', ["\n"]],
159            ['deleted_open', []],
160            ['cdata', ["line\nline\nline"]],
161            ['deleted_close', []],
162            ['cdata', ['']],
163            ['p_close', []],
164            ['document_end', []],
165        ];
166        $this->assertCalls($calls, $this->H->calls);
167    }
168
169    function testDoesNotSpanParagraphBoundary()
170    {
171        // An unclosed `~~` followed by a blank line must stay literal.
172        // Mirrors GFM spec example 492.
173        $this->P->addMode('gfm_deleted', new GfmDeleted());
174        $this->P->parse("This ~~has a\n\nnew paragraph~~.");
175        $modes = array_column($this->H->calls, 0);
176        $this->assertNotContains('deleted_open', $modes,
177            'GfmDeleted must not open when the closing `~~` is past a blank line');
178    }
179
180    function testAllowsSingleNewline()
181    {
182        $this->P->addMode('gfm_deleted', new GfmDeleted());
183        $this->P->parse("~~open\nclose~~");
184        $modes = array_column($this->H->calls, 0);
185        $this->assertContains('deleted_open', $modes,
186            'GfmDeleted must still match across a single newline');
187    }
188
189    function testTrailingWhitespaceBeforeCloserDoesNotStrike()
190    {
191        $this->P->addMode('gfm_deleted', new GfmDeleted());
192        $this->P->parse('~~foo bar ~~');
193        $modes = array_column($this->H->calls, 0);
194        $this->assertNotContains('deleted_open', $modes,
195            'Closer preceded by whitespace must not match');
196    }
197
198    function testSortValue()
199    {
200        $mode = new GfmDeleted();
201        $this->assertSame(130, $mode->getSort());
202    }
203}
204