xref: /dokuwiki/_test/tests/Parsing/ParserMode/GfmMediaTest.php (revision b73ece99c18919754d993a1d1f5cb27140555705)
1<?php
2
3namespace dokuwiki\test\Parsing\ParserMode;
4
5use dokuwiki\Parsing\ParserMode\GfmLink;
6use dokuwiki\Parsing\ParserMode\GfmMedia;
7
8/**
9 * Tests for GFM inline image syntax `![alt](url)` dispatching to DokuWiki's
10 * internalmedia / externalmedia handler instructions.
11 */
12class GfmMediaTest extends ParserTestBase
13{
14    public function setUp(): void
15    {
16        parent::setUp();
17        $this->setSyntax('md');
18    }
19
20    function testInternalMedia()
21    {
22        $this->P->addMode('gfm_media', new GfmMedia());
23        $this->P->parse('Foo ![alt](wiki:image.png) Bar');
24        $calls = [
25            ['document_start', []],
26            ['p_open', []],
27            ['cdata', ["\nFoo "]],
28            ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'details']],
29            ['cdata', [' Bar']],
30            ['p_close', []],
31            ['document_end', []],
32        ];
33        $this->assertCalls($calls, $this->H->calls);
34    }
35
36    function testExternalMediaHttps()
37    {
38        $this->P->addMode('gfm_media', new GfmMedia());
39        $this->P->parse('Foo ![logo](https://example.com/img.png) Bar');
40        $calls = [
41            ['document_start', []],
42            ['p_open', []],
43            ['cdata', ["\nFoo "]],
44            ['externalmedia', ['https://example.com/img.png', 'logo', null, null, null, 'cache', 'details']],
45            ['cdata', [' Bar']],
46            ['p_close', []],
47            ['document_end', []],
48        ];
49        $this->assertCalls($calls, $this->H->calls);
50    }
51
52    function testExternalMediaInterwiki()
53    {
54        $this->P->addMode('gfm_media', new GfmMedia());
55        $this->P->parse('Foo ![foo](wp>Example.png) Bar');
56        $calls = [
57            ['document_start', []],
58            ['p_open', []],
59            ['cdata', ["\nFoo "]],
60            ['externalmedia', ['wp>Example.png', 'foo', null, null, null, 'cache', 'details']],
61            ['cdata', [' Bar']],
62            ['p_close', []],
63            ['document_end', []],
64        ];
65        $this->assertCalls($calls, $this->H->calls);
66    }
67
68    function testEmptyAlt()
69    {
70        // GFM allows `![](/url)` with empty alt; we pass null in the caption
71        // slot to match how DW's Media mode emits no-caption media.
72        $this->P->addMode('gfm_media', new GfmMedia());
73        $this->P->parse('Foo ![](image.png) Bar');
74        $calls = [
75            ['document_start', []],
76            ['p_open', []],
77            ['cdata', ["\nFoo "]],
78            ['internalmedia', ['image.png', null, null, null, null, 'cache', 'details']],
79            ['cdata', [' Bar']],
80            ['p_close', []],
81            ['document_end', []],
82        ];
83        $this->assertCalls($calls, $this->H->calls);
84    }
85
86    function testTitleInDoubleQuotesIsDiscarded()
87    {
88        // GFM allows ![alt](url "title") but DokuWiki's media handler has
89        // no separate title slot (alt doubles as caption). The title parses
90        // cleanly but is dropped.
91        $this->P->addMode('gfm_media', new GfmMedia());
92        $this->P->parse('Foo ![alt](wiki:image.png "caption") Bar');
93        $calls = [
94            ['document_start', []],
95            ['p_open', []],
96            ['cdata', ["\nFoo "]],
97            ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'details']],
98            ['cdata', [' Bar']],
99            ['p_close', []],
100            ['document_end', []],
101        ];
102        $this->assertCalls($calls, $this->H->calls);
103    }
104
105    function testTitleInSingleQuotesIsDiscarded()
106    {
107        $this->P->addMode('gfm_media', new GfmMedia());
108        $this->P->parse("Foo ![alt](wiki:image.png 'caption') Bar");
109        $calls = [
110            ['document_start', []],
111            ['p_open', []],
112            ['cdata', ["\nFoo "]],
113            ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'details']],
114            ['cdata', [' Bar']],
115            ['p_close', []],
116            ['document_end', []],
117        ];
118        $this->assertCalls($calls, $this->H->calls);
119    }
120
121    function testMultibyteAlt()
122    {
123        $this->P->addMode('gfm_media', new GfmMedia());
124        $this->P->parse('Foo ![日本語](pic.png) Bar');
125        $calls = [
126            ['document_start', []],
127            ['p_open', []],
128            ['cdata', ["\nFoo "]],
129            ['internalmedia', ['pic.png', '日本語', null, null, null, 'cache', 'details']],
130            ['cdata', [' Bar']],
131            ['p_close', []],
132            ['document_end', []],
133        ];
134        $this->assertCalls($calls, $this->H->calls);
135    }
136
137    function testPlainLinkNotImage()
138    {
139        // With both gfm_media and gfm_link loaded, `[text](url)` (no leading
140        // `!`) must dispatch through gfm_link, not gfm_media.
141        $this->P->addMode('gfm_media', new GfmMedia());
142        $this->P->addMode('gfm_link', new GfmLink());
143        $this->P->parse('Foo [text](page) Bar');
144        $modes = array_column($this->H->calls, 0);
145        $this->assertContains('internallink', $modes);
146        $this->assertNotContains('internalmedia', $modes);
147    }
148
149    function testBangAloneIsNotImage()
150    {
151        $this->P->addMode('gfm_media', new GfmMedia());
152        $this->P->parse('Foo ![alt] Bar');
153        $modes = array_column($this->H->calls, 0);
154        $this->assertNotContains('internalmedia', $modes);
155        $this->assertNotContains('externalmedia', $modes);
156    }
157
158    function testSpaceBetweenBracketsAndParensIsNotAnImage()
159    {
160        $this->P->addMode('gfm_media', new GfmMedia());
161        $this->P->parse('![foo] (bar)');
162        $modes = array_column($this->H->calls, 0);
163        $this->assertNotContains('internalmedia', $modes);
164        $this->assertNotContains('externalmedia', $modes);
165    }
166
167    function testReferenceStyleImageNotMatched()
168    {
169        $this->P->addMode('gfm_media', new GfmMedia());
170        $this->P->parse('![foo][bar]');
171        $modes = array_column($this->H->calls, 0);
172        $this->assertNotContains('internalmedia', $modes);
173        $this->assertNotContains('externalmedia', $modes);
174    }
175
176    function testTwoImagesInOneLine()
177    {
178        $this->P->addMode('gfm_media', new GfmMedia());
179        $this->P->parse('Foo ![one](a.png) and ![two](b.png) Bar');
180        $calls = [
181            ['document_start', []],
182            ['p_open', []],
183            ['cdata', ["\nFoo "]],
184            ['internalmedia', ['a.png', 'one', null, null, null, 'cache', 'details']],
185            ['cdata', [' and ']],
186            ['internalmedia', ['b.png', 'two', null, null, null, 'cache', 'details']],
187            ['cdata', [' Bar']],
188            ['p_close', []],
189            ['document_end', []],
190        ];
191        $this->assertCalls($calls, $this->H->calls);
192    }
193
194    function testWidthOnlyParameter()
195    {
196        $this->P->addMode('gfm_media', new GfmMedia());
197        $this->P->parse('Foo ![alt](wiki:image.png?200) Bar');
198        $calls = [
199            ['document_start', []],
200            ['p_open', []],
201            ['cdata', ["\nFoo "]],
202            ['internalmedia', ['wiki:image.png', 'alt', null, '200', null, 'cache', 'details']],
203            ['cdata', [' Bar']],
204            ['p_close', []],
205            ['document_end', []],
206        ];
207        $this->assertCalls($calls, $this->H->calls);
208    }
209
210    function testWidthAndHeightParameter()
211    {
212        $this->P->addMode('gfm_media', new GfmMedia());
213        $this->P->parse('Foo ![alt](wiki:image.png?200x100) Bar');
214        $calls = [
215            ['document_start', []],
216            ['p_open', []],
217            ['cdata', ["\nFoo "]],
218            ['internalmedia', ['wiki:image.png', 'alt', null, '200', '100', 'cache', 'details']],
219            ['cdata', [' Bar']],
220            ['p_close', []],
221            ['document_end', []],
222        ];
223        $this->assertCalls($calls, $this->H->calls);
224    }
225
226    function testLinkingParameter()
227    {
228        $this->P->addMode('gfm_media', new GfmMedia());
229        $this->P->parse('Foo ![alt](wiki:image.png?nolink) Bar');
230        $calls = [
231            ['document_start', []],
232            ['p_open', []],
233            ['cdata', ["\nFoo "]],
234            ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'nolink']],
235            ['cdata', [' Bar']],
236            ['p_close', []],
237            ['document_end', []],
238        ];
239        $this->assertCalls($calls, $this->H->calls);
240    }
241
242    function testCacheParameter()
243    {
244        $this->P->addMode('gfm_media', new GfmMedia());
245        $this->P->parse('Foo ![alt](wiki:image.png?recache) Bar');
246        $calls = [
247            ['document_start', []],
248            ['p_open', []],
249            ['cdata', ["\nFoo "]],
250            ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'recache', 'details']],
251            ['cdata', [' Bar']],
252            ['p_close', []],
253            ['document_end', []],
254        ];
255        $this->assertCalls($calls, $this->H->calls);
256    }
257
258    function testCombinedParameters()
259    {
260        $this->P->addMode('gfm_media', new GfmMedia());
261        $this->P->parse('Foo ![alt](wiki:image.png?200x100&nolink&nocache) Bar');
262        $calls = [
263            ['document_start', []],
264            ['p_open', []],
265            ['cdata', ["\nFoo "]],
266            ['internalmedia', ['wiki:image.png', 'alt', null, '200', '100', 'nocache', 'nolink']],
267            ['cdata', [' Bar']],
268            ['p_close', []],
269            ['document_end', []],
270        ];
271        $this->assertCalls($calls, $this->H->calls);
272    }
273
274    function testLastQuestionMarkIsTheParameterDelimiter()
275    {
276        // URLs may carry their own query string; DW splits on the *last* `?`
277        // so the URL query survives as part of the src.
278        $this->P->addMode('gfm_media', new GfmMedia());
279        $this->P->parse('Foo ![alt](https://example.com/img?v=2?200x100) Bar');
280        $calls = [
281            ['document_start', []],
282            ['p_open', []],
283            ['cdata', ["\nFoo "]],
284            ['externalmedia', ['https://example.com/img?v=2', 'alt', null, '200', '100', 'cache', 'details']],
285            ['cdata', [' Bar']],
286            ['p_close', []],
287            ['document_end', []],
288        ];
289        $this->assertCalls($calls, $this->H->calls);
290    }
291
292    function testAlignRight()
293    {
294        // GFM has no native image-alignment syntax, so GfmMedia borrows
295        // DW's ?right/?left/?center keyword from the shared URL parameter
296        // block — the only way to align an inline GFM image.
297        $this->P->addMode('gfm_media', new GfmMedia());
298        $this->P->parse('Foo ![alt](wiki:image.png?right) Bar');
299        $calls = [
300            ['document_start', []],
301            ['p_open', []],
302            ['cdata', ["\nFoo "]],
303            ['internalmedia', ['wiki:image.png', 'alt', 'right', null, null, 'cache', 'details']],
304            ['cdata', [' Bar']],
305            ['p_close', []],
306            ['document_end', []],
307        ];
308        $this->assertCalls($calls, $this->H->calls);
309    }
310
311    function testAlignWithSizeAndLinking()
312    {
313        $this->P->addMode('gfm_media', new GfmMedia());
314        $this->P->parse('Foo ![alt](wiki:image.png?200x100&center&nolink) Bar');
315        $calls = [
316            ['document_start', []],
317            ['p_open', []],
318            ['cdata', ["\nFoo "]],
319            ['internalmedia', ['wiki:image.png', 'alt', 'center', '200', '100', 'cache', 'nolink']],
320            ['cdata', [' Bar']],
321            ['p_close', []],
322            ['document_end', []],
323        ];
324        $this->assertCalls($calls, $this->H->calls);
325    }
326
327    function testSortValue()
328    {
329        $this->assertSame(310, (new GfmMedia())->getSort());
330    }
331}
332