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