13440a8c0SAndreas Gohr<?php 23440a8c0SAndreas Gohr 33440a8c0SAndreas Gohrnamespace dokuwiki\test\Parsing\ParserMode; 43440a8c0SAndreas Gohr 53440a8c0SAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmLink; 63440a8c0SAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmMedia; 73440a8c0SAndreas Gohr 83440a8c0SAndreas Gohr/** 93440a8c0SAndreas Gohr * Tests for GFM inline image syntax `` dispatching to DokuWiki's 103440a8c0SAndreas Gohr * internalmedia / externalmedia handler instructions. 113440a8c0SAndreas Gohr */ 123440a8c0SAndreas Gohrclass GfmMediaTest extends ParserTestBase 133440a8c0SAndreas Gohr{ 143440a8c0SAndreas Gohr public function setUp(): void 153440a8c0SAndreas Gohr { 163440a8c0SAndreas Gohr parent::setUp(); 17*47a02a10SAndreas Gohr $this->setSyntax('md'); 183440a8c0SAndreas Gohr } 193440a8c0SAndreas Gohr 203440a8c0SAndreas Gohr function testInternalMedia() 213440a8c0SAndreas Gohr { 223440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 233440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 243440a8c0SAndreas Gohr $calls = [ 253440a8c0SAndreas Gohr ['document_start', []], 263440a8c0SAndreas Gohr ['p_open', []], 273440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 283440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'details']], 293440a8c0SAndreas Gohr ['cdata', [' Bar']], 303440a8c0SAndreas Gohr ['p_close', []], 313440a8c0SAndreas Gohr ['document_end', []], 323440a8c0SAndreas Gohr ]; 333440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 343440a8c0SAndreas Gohr } 353440a8c0SAndreas Gohr 363440a8c0SAndreas Gohr function testExternalMediaHttps() 373440a8c0SAndreas Gohr { 383440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 393440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 403440a8c0SAndreas Gohr $calls = [ 413440a8c0SAndreas Gohr ['document_start', []], 423440a8c0SAndreas Gohr ['p_open', []], 433440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 443440a8c0SAndreas Gohr ['externalmedia', ['https://example.com/img.png', 'logo', null, null, null, 'cache', 'details']], 453440a8c0SAndreas Gohr ['cdata', [' Bar']], 463440a8c0SAndreas Gohr ['p_close', []], 473440a8c0SAndreas Gohr ['document_end', []], 483440a8c0SAndreas Gohr ]; 493440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 503440a8c0SAndreas Gohr } 513440a8c0SAndreas Gohr 523440a8c0SAndreas Gohr function testExternalMediaInterwiki() 533440a8c0SAndreas Gohr { 543440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 553440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 563440a8c0SAndreas Gohr $calls = [ 573440a8c0SAndreas Gohr ['document_start', []], 583440a8c0SAndreas Gohr ['p_open', []], 593440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 603440a8c0SAndreas Gohr ['externalmedia', ['wp>Example.png', 'foo', null, null, null, 'cache', 'details']], 613440a8c0SAndreas Gohr ['cdata', [' Bar']], 623440a8c0SAndreas Gohr ['p_close', []], 633440a8c0SAndreas Gohr ['document_end', []], 643440a8c0SAndreas Gohr ]; 653440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 663440a8c0SAndreas Gohr } 673440a8c0SAndreas Gohr 683440a8c0SAndreas Gohr function testEmptyAlt() 693440a8c0SAndreas Gohr { 703440a8c0SAndreas Gohr // GFM allows `` with empty alt; we pass null in the caption 713440a8c0SAndreas Gohr // slot to match how DW's Media mode emits no-caption media. 723440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 733440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 743440a8c0SAndreas Gohr $calls = [ 753440a8c0SAndreas Gohr ['document_start', []], 763440a8c0SAndreas Gohr ['p_open', []], 773440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 783440a8c0SAndreas Gohr ['internalmedia', ['image.png', null, null, null, null, 'cache', 'details']], 793440a8c0SAndreas Gohr ['cdata', [' Bar']], 803440a8c0SAndreas Gohr ['p_close', []], 813440a8c0SAndreas Gohr ['document_end', []], 823440a8c0SAndreas Gohr ]; 833440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 843440a8c0SAndreas Gohr } 853440a8c0SAndreas Gohr 863440a8c0SAndreas Gohr function testTitleInDoubleQuotesIsDiscarded() 873440a8c0SAndreas Gohr { 883440a8c0SAndreas Gohr // GFM allows  but DokuWiki's media handler has 893440a8c0SAndreas Gohr // no separate title slot (alt doubles as caption). The title parses 903440a8c0SAndreas Gohr // cleanly but is dropped. 913440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 923440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 933440a8c0SAndreas Gohr $calls = [ 943440a8c0SAndreas Gohr ['document_start', []], 953440a8c0SAndreas Gohr ['p_open', []], 963440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 973440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'details']], 983440a8c0SAndreas Gohr ['cdata', [' Bar']], 993440a8c0SAndreas Gohr ['p_close', []], 1003440a8c0SAndreas Gohr ['document_end', []], 1013440a8c0SAndreas Gohr ]; 1023440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 1033440a8c0SAndreas Gohr } 1043440a8c0SAndreas Gohr 1053440a8c0SAndreas Gohr function testTitleInSingleQuotesIsDiscarded() 1063440a8c0SAndreas Gohr { 1073440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1083440a8c0SAndreas Gohr $this->P->parse("Foo  Bar"); 1093440a8c0SAndreas Gohr $calls = [ 1103440a8c0SAndreas Gohr ['document_start', []], 1113440a8c0SAndreas Gohr ['p_open', []], 1123440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 1133440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'details']], 1143440a8c0SAndreas Gohr ['cdata', [' Bar']], 1153440a8c0SAndreas Gohr ['p_close', []], 1163440a8c0SAndreas Gohr ['document_end', []], 1173440a8c0SAndreas Gohr ]; 1183440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 1193440a8c0SAndreas Gohr } 1203440a8c0SAndreas Gohr 1213440a8c0SAndreas Gohr function testMultibyteAlt() 1223440a8c0SAndreas Gohr { 1233440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1243440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 1253440a8c0SAndreas Gohr $calls = [ 1263440a8c0SAndreas Gohr ['document_start', []], 1273440a8c0SAndreas Gohr ['p_open', []], 1283440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 1293440a8c0SAndreas Gohr ['internalmedia', ['pic.png', '日本語', null, null, null, 'cache', 'details']], 1303440a8c0SAndreas Gohr ['cdata', [' Bar']], 1313440a8c0SAndreas Gohr ['p_close', []], 1323440a8c0SAndreas Gohr ['document_end', []], 1333440a8c0SAndreas Gohr ]; 1343440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 1353440a8c0SAndreas Gohr } 1363440a8c0SAndreas Gohr 1373440a8c0SAndreas Gohr function testPlainLinkNotImage() 1383440a8c0SAndreas Gohr { 1393440a8c0SAndreas Gohr // With both gfm_media and gfm_link loaded, `[text](url)` (no leading 1403440a8c0SAndreas Gohr // `!`) must dispatch through gfm_link, not gfm_media. 1413440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1423440a8c0SAndreas Gohr $this->P->addMode('gfm_link', new GfmLink()); 1433440a8c0SAndreas Gohr $this->P->parse('Foo [text](page) Bar'); 1443440a8c0SAndreas Gohr $modes = array_column($this->H->calls, 0); 1453440a8c0SAndreas Gohr $this->assertContains('internallink', $modes); 1463440a8c0SAndreas Gohr $this->assertNotContains('internalmedia', $modes); 1473440a8c0SAndreas Gohr } 1483440a8c0SAndreas Gohr 1493440a8c0SAndreas Gohr function testBangAloneIsNotImage() 1503440a8c0SAndreas Gohr { 1513440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1523440a8c0SAndreas Gohr $this->P->parse('Foo ![alt] Bar'); 1533440a8c0SAndreas Gohr $modes = array_column($this->H->calls, 0); 1543440a8c0SAndreas Gohr $this->assertNotContains('internalmedia', $modes); 1553440a8c0SAndreas Gohr $this->assertNotContains('externalmedia', $modes); 1563440a8c0SAndreas Gohr } 1573440a8c0SAndreas Gohr 1583440a8c0SAndreas Gohr function testSpaceBetweenBracketsAndParensIsNotAnImage() 1593440a8c0SAndreas Gohr { 1603440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1613440a8c0SAndreas Gohr $this->P->parse('![foo] (bar)'); 1623440a8c0SAndreas Gohr $modes = array_column($this->H->calls, 0); 1633440a8c0SAndreas Gohr $this->assertNotContains('internalmedia', $modes); 1643440a8c0SAndreas Gohr $this->assertNotContains('externalmedia', $modes); 1653440a8c0SAndreas Gohr } 1663440a8c0SAndreas Gohr 1673440a8c0SAndreas Gohr function testReferenceStyleImageNotMatched() 1683440a8c0SAndreas Gohr { 1693440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1703440a8c0SAndreas Gohr $this->P->parse('![foo][bar]'); 1713440a8c0SAndreas Gohr $modes = array_column($this->H->calls, 0); 1723440a8c0SAndreas Gohr $this->assertNotContains('internalmedia', $modes); 1733440a8c0SAndreas Gohr $this->assertNotContains('externalmedia', $modes); 1743440a8c0SAndreas Gohr } 1753440a8c0SAndreas Gohr 1763440a8c0SAndreas Gohr function testTwoImagesInOneLine() 1773440a8c0SAndreas Gohr { 1783440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1793440a8c0SAndreas Gohr $this->P->parse('Foo  and  Bar'); 1803440a8c0SAndreas Gohr $calls = [ 1813440a8c0SAndreas Gohr ['document_start', []], 1823440a8c0SAndreas Gohr ['p_open', []], 1833440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 1843440a8c0SAndreas Gohr ['internalmedia', ['a.png', 'one', null, null, null, 'cache', 'details']], 1853440a8c0SAndreas Gohr ['cdata', [' and ']], 1863440a8c0SAndreas Gohr ['internalmedia', ['b.png', 'two', null, null, null, 'cache', 'details']], 1873440a8c0SAndreas Gohr ['cdata', [' Bar']], 1883440a8c0SAndreas Gohr ['p_close', []], 1893440a8c0SAndreas Gohr ['document_end', []], 1903440a8c0SAndreas Gohr ]; 1913440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 1923440a8c0SAndreas Gohr } 1933440a8c0SAndreas Gohr 1943440a8c0SAndreas Gohr function testWidthOnlyParameter() 1953440a8c0SAndreas Gohr { 1963440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 1973440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 1983440a8c0SAndreas Gohr $calls = [ 1993440a8c0SAndreas Gohr ['document_start', []], 2003440a8c0SAndreas Gohr ['p_open', []], 2013440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 2023440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, '200', null, 'cache', 'details']], 2033440a8c0SAndreas Gohr ['cdata', [' Bar']], 2043440a8c0SAndreas Gohr ['p_close', []], 2053440a8c0SAndreas Gohr ['document_end', []], 2063440a8c0SAndreas Gohr ]; 2073440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 2083440a8c0SAndreas Gohr } 2093440a8c0SAndreas Gohr 2103440a8c0SAndreas Gohr function testWidthAndHeightParameter() 2113440a8c0SAndreas Gohr { 2123440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 2133440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 2143440a8c0SAndreas Gohr $calls = [ 2153440a8c0SAndreas Gohr ['document_start', []], 2163440a8c0SAndreas Gohr ['p_open', []], 2173440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 2183440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, '200', '100', 'cache', 'details']], 2193440a8c0SAndreas Gohr ['cdata', [' Bar']], 2203440a8c0SAndreas Gohr ['p_close', []], 2213440a8c0SAndreas Gohr ['document_end', []], 2223440a8c0SAndreas Gohr ]; 2233440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 2243440a8c0SAndreas Gohr } 2253440a8c0SAndreas Gohr 2263440a8c0SAndreas Gohr function testLinkingParameter() 2273440a8c0SAndreas Gohr { 2283440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 2293440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 2303440a8c0SAndreas Gohr $calls = [ 2313440a8c0SAndreas Gohr ['document_start', []], 2323440a8c0SAndreas Gohr ['p_open', []], 2333440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 2343440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'cache', 'nolink']], 2353440a8c0SAndreas Gohr ['cdata', [' Bar']], 2363440a8c0SAndreas Gohr ['p_close', []], 2373440a8c0SAndreas Gohr ['document_end', []], 2383440a8c0SAndreas Gohr ]; 2393440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 2403440a8c0SAndreas Gohr } 2413440a8c0SAndreas Gohr 2423440a8c0SAndreas Gohr function testCacheParameter() 2433440a8c0SAndreas Gohr { 2443440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 2453440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 2463440a8c0SAndreas Gohr $calls = [ 2473440a8c0SAndreas Gohr ['document_start', []], 2483440a8c0SAndreas Gohr ['p_open', []], 2493440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 2503440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, null, null, 'recache', 'details']], 2513440a8c0SAndreas Gohr ['cdata', [' Bar']], 2523440a8c0SAndreas Gohr ['p_close', []], 2533440a8c0SAndreas Gohr ['document_end', []], 2543440a8c0SAndreas Gohr ]; 2553440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 2563440a8c0SAndreas Gohr } 2573440a8c0SAndreas Gohr 2583440a8c0SAndreas Gohr function testCombinedParameters() 2593440a8c0SAndreas Gohr { 2603440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 2613440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 2623440a8c0SAndreas Gohr $calls = [ 2633440a8c0SAndreas Gohr ['document_start', []], 2643440a8c0SAndreas Gohr ['p_open', []], 2653440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 2663440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', null, '200', '100', 'nocache', 'nolink']], 2673440a8c0SAndreas Gohr ['cdata', [' Bar']], 2683440a8c0SAndreas Gohr ['p_close', []], 2693440a8c0SAndreas Gohr ['document_end', []], 2703440a8c0SAndreas Gohr ]; 2713440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 2723440a8c0SAndreas Gohr } 2733440a8c0SAndreas Gohr 2743440a8c0SAndreas Gohr function testLastQuestionMarkIsTheParameterDelimiter() 2753440a8c0SAndreas Gohr { 2763440a8c0SAndreas Gohr // URLs may carry their own query string; DW splits on the *last* `?` 2773440a8c0SAndreas Gohr // so the URL query survives as part of the src. 2783440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 2793440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 2803440a8c0SAndreas Gohr $calls = [ 2813440a8c0SAndreas Gohr ['document_start', []], 2823440a8c0SAndreas Gohr ['p_open', []], 2833440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 2843440a8c0SAndreas Gohr ['externalmedia', ['https://example.com/img?v=2', 'alt', null, '200', '100', 'cache', 'details']], 2853440a8c0SAndreas Gohr ['cdata', [' Bar']], 2863440a8c0SAndreas Gohr ['p_close', []], 2873440a8c0SAndreas Gohr ['document_end', []], 2883440a8c0SAndreas Gohr ]; 2893440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 2903440a8c0SAndreas Gohr } 2913440a8c0SAndreas Gohr 2923440a8c0SAndreas Gohr function testAlignRight() 2933440a8c0SAndreas Gohr { 2943440a8c0SAndreas Gohr // GFM has no native image-alignment syntax, so GfmMedia borrows 2953440a8c0SAndreas Gohr // DW's ?right/?left/?center keyword from the shared URL parameter 2963440a8c0SAndreas Gohr // block — the only way to align an inline GFM image. 2973440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 2983440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 2993440a8c0SAndreas Gohr $calls = [ 3003440a8c0SAndreas Gohr ['document_start', []], 3013440a8c0SAndreas Gohr ['p_open', []], 3023440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 3033440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', 'right', null, null, 'cache', 'details']], 3043440a8c0SAndreas Gohr ['cdata', [' Bar']], 3053440a8c0SAndreas Gohr ['p_close', []], 3063440a8c0SAndreas Gohr ['document_end', []], 3073440a8c0SAndreas Gohr ]; 3083440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 3093440a8c0SAndreas Gohr } 3103440a8c0SAndreas Gohr 3113440a8c0SAndreas Gohr function testAlignWithSizeAndLinking() 3123440a8c0SAndreas Gohr { 3133440a8c0SAndreas Gohr $this->P->addMode('gfm_media', new GfmMedia()); 3143440a8c0SAndreas Gohr $this->P->parse('Foo  Bar'); 3153440a8c0SAndreas Gohr $calls = [ 3163440a8c0SAndreas Gohr ['document_start', []], 3173440a8c0SAndreas Gohr ['p_open', []], 3183440a8c0SAndreas Gohr ['cdata', ["\nFoo "]], 3193440a8c0SAndreas Gohr ['internalmedia', ['wiki:image.png', 'alt', 'center', '200', '100', 'cache', 'nolink']], 3203440a8c0SAndreas Gohr ['cdata', [' Bar']], 3213440a8c0SAndreas Gohr ['p_close', []], 3223440a8c0SAndreas Gohr ['document_end', []], 3233440a8c0SAndreas Gohr ]; 3243440a8c0SAndreas Gohr $this->assertCalls($calls, $this->H->calls); 3253440a8c0SAndreas Gohr } 3263440a8c0SAndreas Gohr 3273440a8c0SAndreas Gohr function testSortValue() 3283440a8c0SAndreas Gohr { 3293440a8c0SAndreas Gohr $this->assertSame(310, (new GfmMedia())->getSort()); 3303440a8c0SAndreas Gohr } 3313440a8c0SAndreas Gohr} 332