1<?php 2 3namespace dokuwiki\test\Parsing\ParserMode; 4 5use Doku_Renderer_xhtml; 6use dokuwiki\Parsing\ParserMode\Media; 7 8/** 9 * Tests for the {@see Media} parser mode: `{{...}}` media embeds. 10 * 11 * Covers the parser-level dispatch (internalmedia/externalmedia calls with the right argument tuple), 12 * audio/video rendering through the XHTML renderer, and various title / alignment / cache flag cases. 13 * 14 * @group parser_media 15 * @author Michael Große <grosse@cosmocode.de> 16*/ 17class MediaTest extends ParserTestBase 18{ 19 function testInternal() { 20 $this->P->addMode('media', new Media()); 21 $this->P->parse('Foo {{img.gif}} Bar'); 22 $calls = [ 23 ['document_start', []], 24 ['p_open', []], 25 ['cdata', ["\n" . 'Foo ']], 26 ['internalmedia', ['img.gif', null, null, null, null, 'cache', 'details']], 27 ['cdata', [' Bar']], 28 ['p_close', []], 29 ['document_end', []], 30 ]; 31 $this->assertCalls($calls, $this->H->calls); 32 } 33 34 function testInternalLinkOnly() { 35 $this->P->addMode('media', new Media()); 36 $this->P->parse('Foo {{img.gif?linkonly}} Bar'); 37 $calls = [ 38 ['document_start', []], 39 ['p_open', []], 40 ['cdata', ["\n" . 'Foo ']], 41 ['internalmedia', ['img.gif', null, null, null, null, 'cache', 'linkonly']], 42 ['cdata', [' Bar']], 43 ['p_close', []], 44 ['document_end', []], 45 ]; 46 $this->assertCalls($calls, $this->H->calls); 47 } 48 49 function testNotImage() { 50 $this->P->addMode('media', new Media()); 51 $this->P->parse('Foo {{foo.txt?10x10|Some File}} Bar'); 52 $calls = [ 53 ['document_start', []], 54 ['p_open', []], 55 ['cdata', ["\n" . 'Foo ']], 56 ['internalmedia', ['foo.txt', 'Some File', null, 10, 10, 'cache', 'details']], 57 ['cdata', [' Bar']], 58 ['p_close', []], 59 ['document_end', []], 60 ]; 61 $this->assertCalls($calls, $this->H->calls); 62 } 63 64 function testInternalLAlign() { 65 $this->P->addMode('media', new Media()); 66 $this->P->parse('Foo {{img.gif }} Bar'); 67 $calls = [ 68 ['document_start', []], 69 ['p_open', []], 70 ['cdata', ["\n" . 'Foo ']], 71 ['internalmedia', ['img.gif', null, 'left', null, null, 'cache', 'details']], 72 ['cdata', [' Bar']], 73 ['p_close', []], 74 ['document_end', []], 75 ]; 76 $this->assertCalls($calls, $this->H->calls); 77 } 78 79 function testInternalRAlign() { 80 $this->P->addMode('media', new Media()); 81 $this->P->parse('Foo {{ img.gif}} Bar'); 82 $calls = [ 83 ['document_start', []], 84 ['p_open', []], 85 ['cdata', ["\n" . 'Foo ']], 86 ['internalmedia', ['img.gif', null, 'right', null, null, 'cache', 'details']], 87 ['cdata', [' Bar']], 88 ['p_close', []], 89 ['document_end', []], 90 ]; 91 $this->assertCalls($calls, $this->H->calls); 92 } 93 94 function testInternalCenter() { 95 $this->P->addMode('media', new Media()); 96 $this->P->parse('Foo {{ img.gif }} Bar'); 97 $calls = [ 98 ['document_start', []], 99 ['p_open', []], 100 ['cdata', ["\n" . 'Foo ']], 101 ['internalmedia', ['img.gif', null, 'center', null, null, 'cache', 'details']], 102 ['cdata', [' Bar']], 103 ['p_close', []], 104 ['document_end', []], 105 ]; 106 $this->assertCalls($calls, $this->H->calls); 107 } 108 109 function testInternalParams() { 110 $this->P->addMode('media', new Media()); 111 $this->P->parse('Foo {{img.gif?50x100nocache}} Bar'); 112 $calls = [ 113 ['document_start', []], 114 ['p_open', []], 115 ['cdata', ["\n" . 'Foo ']], 116 ['internalmedia', ['img.gif', null, null, '50', '100', 'nocache', 'details']], 117 ['cdata', [' Bar']], 118 ['p_close', []], 119 ['document_end', []], 120 ]; 121 $this->assertCalls($calls, $this->H->calls); 122 } 123 124 function testInternalTitle() { 125 $this->P->addMode('media', new Media()); 126 $this->P->parse('Foo {{img.gif?50x100|Some Image}} Bar'); 127 $calls = [ 128 ['document_start', []], 129 ['p_open', []], 130 ['cdata', ["\n" . 'Foo ']], 131 ['internalmedia', ['img.gif', 'Some Image', null, '50', '100', 'cache', 'details']], 132 ['cdata', [' Bar']], 133 ['p_close', []], 134 ['document_end', []], 135 ]; 136 $this->assertCalls($calls, $this->H->calls); 137 } 138 139 function testExternal() { 140 $this->P->addMode('media', new Media()); 141 $this->P->parse('Foo {{http://www.google.com/img.gif}} Bar'); 142 $calls = [ 143 ['document_start', []], 144 ['p_open', []], 145 ['cdata', ["\n" . 'Foo ']], 146 ['externalmedia', ['http://www.google.com/img.gif', null, null, null, null, 'cache', 'details']], 147 ['cdata', [' Bar']], 148 ['p_close', []], 149 ['document_end', []], 150 ]; 151 $this->assertCalls($calls, $this->H->calls); 152 } 153 154 function testExternalParams() { 155 $this->P->addMode('media', new Media()); 156 $this->P->parse('Foo {{http://www.google.com/img.gif?50x100nocache}} Bar'); 157 $calls = [ 158 ['document_start', []], 159 ['p_open', []], 160 ['cdata', ["\n" . 'Foo ']], 161 ['externalmedia', 162 ['http://www.google.com/img.gif', null, null, '50', '100', 'nocache', 'details']], 163 ['cdata', [' Bar']], 164 ['p_close', []], 165 ['document_end', []], 166 ]; 167 $this->assertCalls($calls, $this->H->calls); 168 } 169 170 function testExternalTitle() { 171 $this->P->addMode('media', new Media()); 172 $this->P->parse('Foo {{http://www.google.com/img.gif?50x100|Some Image}} Bar'); 173 $calls = [ 174 ['document_start', []], 175 ['p_open', []], 176 ['cdata', ["\n" . 'Foo ']], 177 ['externalmedia', 178 ['http://www.google.com/img.gif', 'Some Image', null, '50', '100', 'cache', 'details']], 179 ['cdata', [' Bar']], 180 ['p_close', []], 181 ['document_end', []], 182 ]; 183 $this->assertCalls($calls, $this->H->calls); 184 } 185 186 function testNested() { 187 $this->P->addMode('media', new Media()); 188 $this->P->parse('Foo {{img.gif|{{foo.gif|{{bar.gif|Bar}}}}}} Bar'); 189 $calls = [ 190 ['document_start', []], 191 ['p_open', []], 192 ['cdata', ["\n" . 'Foo ']], 193 ['internalmedia', 194 ['img.gif', '{{foo.gif|{{bar.gif|Bar', null, null, null, 'cache', 'details']], 195 ['cdata', ['}}}} Bar']], 196 ['p_close', []], 197 ['document_end', []], 198 ]; 199 $this->assertCalls($calls, $this->H->calls); 200 } 201 202 203 function testVideoOGVExternal() { 204 $file = 'http://some.where.far/away.ogv'; 205 $parser_response = p_get_instructions('{{' . $file . '}}'); 206 207 $calls = [ 208 ['document_start',[]], 209 ['p_open',[]], 210 ['externalmedia',[$file,null,null,null,null,'cache','details']], 211 ['cdata',[null]], 212 ['p_close',[]], 213 ['document_end',[]], 214 ]; 215 $this->assertCalls($calls, $parser_response); 216 217 $Renderer = new Doku_Renderer_xhtml(); 218 $url = $Renderer->externalmedia($file,null,null,null,null,'cache','details',true); 219 //print_r("url: " . $url); 220 $video = '<video class="media" width="320" height="240" controls="controls">'; 221 $this->assertEquals($video, substr($url,0,66)); 222 $source = '<source src="http://some.where.far/away.ogv" type="video/ogg" />'; 223 $this->assertEquals($source, substr($url,67,64)); 224 // work around random token 225 $a_first_part = '<a href="' . \DOKU_BASE . 'lib/exe/fetch.php?tok='; 226 $a_second_part = '&media=http%3A%2F%2Fsome.where.far%2Faway.ogv" class="media mediafile mf_ogv" title="http://some.where.far/away.ogv">'; 227 228 $substr_start = 132; 229 $substr_len = strlen($a_first_part); 230 $this->assertEquals($a_first_part, substr($url, $substr_start, $substr_len)); 231 232 $substr_start = strpos($url, '&media', $substr_start + $substr_len); 233 $this->assertNotSame(false, $substr_start, 'Substring not found.'); 234 $substr_len = strlen($a_second_part); 235 $this->assertEquals($a_second_part, substr($url, $substr_start, $substr_len)); 236 237 $rest = 'away.ogv</a></video>'."\n"; 238 $substr_start = strlen($url) - strlen($rest); 239 $this->assertEquals($rest, substr($url, $substr_start)); 240 } 241 242 /** 243 * unknown extension of external media file 244 */ 245 function testVideoVIDExternal() { 246 $file = 'http://some.where.far/away.vid'; 247 $parser_response = p_get_instructions('{{' . $file . '}}'); 248 249 $calls = [ 250 ['document_start', []], 251 ['p_open', []], 252 ['externalmedia', [$file, null, null, null, null, 'cache', 'details']], 253 ['cdata', [null]], 254 ['p_close', []], 255 ['document_end', []], 256 ]; 257 $this->assertCalls($calls, $parser_response); 258 259 $Renderer = new Doku_Renderer_xhtml(); 260 $url = $Renderer->externalmedia($file, null, null, null, null, 'cache', 'details', true); 261 // work around random token 262 $a_first_part = '<a href="' . \DOKU_BASE . 'lib/exe/fetch.php?tok='; 263 $a_second_part = '&media=http%3A%2F%2Fsome.where.far%2Faway.vid" class="media mediafile mf_vid" title="http://some.where.far/away.vid">'; 264 265 $substr_start = 0; 266 $substr_len = strlen($a_first_part); 267 $this->assertEquals($a_first_part, substr($url, $substr_start, $substr_len)); 268 269 $substr_start = strpos($url, '&media', $substr_start + $substr_len); 270 $this->assertNotSame(false, $substr_start, 'Substring not found.'); 271 $substr_len = strlen($a_second_part); 272 $this->assertEquals($a_second_part, substr($url, $substr_start, $substr_len)); 273 274 $rest = 'away.vid</a>'; 275 $substr_start = strlen($url) - strlen($rest); 276 $this->assertEquals($rest, substr($url, $substr_start)); 277 } 278 279 280 function testVideoOGVInternal() { 281 $file = 'wiki:kind_zu_katze.ogv'; 282 $parser_response = p_get_instructions('{{' . $file . '}}'); 283 284 $calls = [ 285 ['document_start',[]], 286 ['p_open',[]], 287 ['internalmedia',[$file,null,null,null,null,'cache','details']], 288 ['cdata',[null]], 289 ['p_close',[]], 290 ['document_end',[]], 291 ]; 292 $this->assertCalls($calls, $parser_response); 293 294 $Renderer = new Doku_Renderer_xhtml(); 295 $url = $Renderer->externalmedia($file,null,null,null,null,'cache','details',true); 296 297 $video = '<video class="media" width="320" height="240" controls="controls" poster="' . \DOKU_BASE . 'lib/exe/fetch.php?media=wiki:kind_zu_katze.png">'; 298 $substr_start = 0; 299 $substr_len = strlen($video); 300 $this->assertEquals($video, substr($url, $substr_start, $substr_len)); 301 302 // find $source_webm in $url 303 $source_webm = '<source src="' . \DOKU_BASE . 'lib/exe/fetch.php?media=wiki:kind_zu_katze.webm" type="video/webm" />'; 304 $substr_start = strpos($url, $source_webm, $substr_start + $substr_len); 305 $this->assertNotSame(false, $substr_start, 'Substring not found.'); 306 307 // find $source_ogv in $url 308 $source_ogv = '<source src="' . \DOKU_BASE . 'lib/exe/fetch.php?media=wiki:kind_zu_katze.ogv" type="video/ogg" />'; 309 $substr_start = strpos($url, $source_ogv, $substr_start + strlen($source_webm)); 310 $this->assertNotSame(false, $substr_start, 'Substring not found.'); 311 312 // find $a_webm in $url 313 $a_webm = '<a href="' . \DOKU_BASE . 'lib/exe/fetch.php?media=wiki:kind_zu_katze.webm" class="media mediafile mf_webm" title="wiki:kind_zu_katze.webm (99.1'."\xC2\xA0".'KB)">kind_zu_katze.webm</a>'; 314 $substr_start = strpos($url, $a_webm, $substr_start + strlen($source_ogv)); 315 $this->assertNotSame(false, $substr_start, 'Substring not found.'); 316 317 // find $a_webm in $url 318 $a_ogv = '<a href="' . \DOKU_BASE . 'lib/exe/fetch.php?media=wiki:kind_zu_katze.ogv" class="media mediafile mf_ogv" title="wiki:kind_zu_katze.ogv (44.8'."\xC2\xA0".'KB)">kind_zu_katze.ogv</a>'; 319 $substr_start = strpos($url, $a_ogv, $substr_start + strlen($a_webm)); 320 $this->assertNotSame(false, $substr_start, 'Substring not found.'); 321 322 $rest = '</video>'."\n"; 323 $substr_start = strlen($url) - strlen($rest); 324 $this->assertEquals($rest, substr($url, $substr_start)); 325 } 326 327 function testVideoInternalTitle() { 328 $file = 'wiki:kind_zu_katze.ogv'; 329 $title = 'Single quote: \' Ampersand: &'; 330 331 $Renderer = new Doku_Renderer_xhtml(); 332 $url = $Renderer->externalmedia($file, $title, null, null, null, 'cache', 'details', true); 333 334 // make sure the title is escaped just once 335 $this->assertEquals(hsc($title), substr($url, 28, 37)); 336 } 337 338 function testSimpleLinkText() { 339 $file = 'wiki:dokuwiki-128.png'; 340 $parser_response = p_get_instructions('{{' . $file . '|This is a simple text.}}'); 341 342 $calls = [ 343 ['document_start',[]], 344 ['p_open',[]], 345 ['internalmedia',[$file,'This is a simple text.',null,null,null,'cache','details']], 346 ['cdata',[null]], 347 ['p_close',[]], 348 ['document_end',[]], 349 ]; 350 $this->assertCalls($calls, $parser_response); 351 } 352 353 function testLinkTextWithWavedBrackets_1() { 354 $file = 'wiki:dokuwiki-128.png'; 355 $parser_response = p_get_instructions('{{' . $file . '|We got a { here.}}'); 356 357 $calls = [ 358 ['document_start',[]], 359 ['p_open',[]], 360 ['internalmedia',[$file,'We got a { here.',null,null,null,'cache','details']], 361 ['cdata',[null]], 362 ['p_close',[]], 363 ['document_end',[]], 364 ]; 365 $this->assertCalls($calls, $parser_response); 366 } 367 368 function testLinkTextWithWavedBrackets_2() { 369 $file = 'wiki:dokuwiki-128.png'; 370 $parser_response = p_get_instructions('{{' . $file . '|We got a } here.}}'); 371 372 $calls = [ 373 ['document_start',[]], 374 ['p_open',[]], 375 ['internalmedia',[$file,'We got a } here.',null,null,null,'cache','details']], 376 ['cdata',[null]], 377 ['p_close',[]], 378 ['document_end',[]], 379 ]; 380 $this->assertCalls($calls, $parser_response); 381 } 382 383 function testAlignFromWhitespace() { 384 // DW's historical whitespace-inside-braces alignment still works. 385 $file = 'wiki:image.png'; 386 $parser_response = p_get_instructions('{{ ' . $file . '}}'); 387 $calls = [ 388 ['document_start', []], 389 ['p_open', []], 390 ['internalmedia', [$file, null, 'right', null, null, 'cache', 'details']], 391 ['cdata', [null]], 392 ['p_close', []], 393 ['document_end', []], 394 ]; 395 $this->assertCalls($calls, $parser_response); 396 } 397 398 function testAlignFromParameter() { 399 $file = 'wiki:image.png'; 400 $parser_response = p_get_instructions('{{' . $file . '?left}}'); 401 $calls = [ 402 ['document_start', []], 403 ['p_open', []], 404 ['internalmedia', [$file, null, 'left', null, null, 'cache', 'details']], 405 ['cdata', [null]], 406 ['p_close', []], 407 ['document_end', []], 408 ]; 409 $this->assertCalls($calls, $parser_response); 410 } 411 412 function testAlignParameterBeatsWhitespace() { 413 // Explicit ?center wins over whitespace-derived 'left' (trailing space). 414 $file = 'wiki:image.png'; 415 $parser_response = p_get_instructions('{{' . $file . '?center }}'); 416 $calls = [ 417 ['document_start', []], 418 ['p_open', []], 419 ['internalmedia', [$file, null, 'center', null, null, 'cache', 'details']], 420 ['cdata', [null]], 421 ['p_close', []], 422 ['document_end', []], 423 ]; 424 $this->assertCalls($calls, $parser_response); 425 } 426 427 function testLinkTextWithWavedBrackets_3() { 428 $file = 'wiki:dokuwiki-128.png'; 429 $parser_response = p_get_instructions('{{' . $file . '|We got a { and a } here.}}'); 430 431 $calls = [ 432 ['document_start',[]], 433 ['p_open',[]], 434 ['internalmedia',[$file,'We got a { and a } here.',null,null,null,'cache','details']], 435 ['cdata',[null]], 436 ['p_close',[]], 437 ['document_end',[]], 438 ]; 439 $this->assertCalls($calls, $parser_response); 440 } 441} 442