1<?php 2 3namespace dokuwiki\test\Parsing; 4 5use dokuwiki\Parsing\Handler; 6use dokuwiki\Parsing\ModeRegistry; 7 8class HandlerTest extends \DokuWikiTest 9{ 10 function testGetModeNameReturnsOriginalName() 11 { 12 $handler = new Handler(new ModeRegistry('dw')); 13 14 // create a simple mode that records what getModeName() returns 15 $mode = new class extends \dokuwiki\Parsing\ParserMode\AbstractMode { 16 public $receivedModeName = ''; 17 public function getSort() { return 0; } 18 public function handle($match, $state, $pos, Handler $handler) 19 { 20 $this->receivedModeName = $handler->getModeName(); 21 return true; 22 } 23 }; 24 25 $handler->registerModeObject('resolved', $mode); 26 27 // simulate dispatch with a remapped name (original differs from resolved) 28 $handler->handleToken('resolved', 'test', DOKU_LEXER_SPECIAL, 0, 'original'); 29 30 $this->assertSame('original', $mode->receivedModeName); 31 } 32 33 function testGetModeNameFallsBackToModeName() 34 { 35 $handler = new Handler(new ModeRegistry('dw')); 36 37 $mode = new class extends \dokuwiki\Parsing\ParserMode\AbstractMode { 38 public $receivedModeName = ''; 39 public function getSort() { return 0; } 40 public function handle($match, $state, $pos, Handler $handler) 41 { 42 $this->receivedModeName = $handler->getModeName(); 43 return true; 44 } 45 }; 46 47 $handler->registerModeObject('mymode', $mode); 48 49 // no original name passed — should fall back to the resolved name 50 $handler->handleToken('mymode', 'test', DOKU_LEXER_SPECIAL, 0); 51 52 $this->assertSame('mymode', $mode->receivedModeName); 53 } 54 55 function testResetClearsCallsAndStatusAndCurrentMode() 56 { 57 $handler = new Handler(new ModeRegistry('dw')); 58 59 // dirty the handler: append a call, mutate status, and prime 60 // currentModeName via a token dispatch. 61 $handler->calls[] = ['cdata', ['x'], 0]; 62 63 self::setInaccessibleProperty($handler, 'status', [ 64 'section' => true, 'doublequote' => 3, 'footnote' => true, 65 ]); 66 67 $mode = new class extends \dokuwiki\Parsing\ParserMode\AbstractMode { 68 public function getSort() 69 { 70 return 0; 71 } 72 73 public function handle($match, $state, $pos, Handler $handler) 74 { 75 return true; 76 } 77 }; 78 $handler->registerModeObject('m', $mode); 79 $handler->handleToken('m', 'x', DOKU_LEXER_SPECIAL, 0, 'm'); 80 $this->assertSame('m', $handler->getModeName()); 81 82 $writerBefore = self::getInaccessibleProperty($handler, 'callWriter'); 83 84 $handler->reset(); 85 86 $this->assertSame([], $handler->calls); 87 $this->assertSame('', $handler->getModeName()); 88 $this->assertSame( 89 ['section' => false, 'doublequote' => 0, 'footnote' => false], 90 self::getInaccessibleProperty($handler, 'status') 91 ); 92 // reset reinstalls a fresh CallWriter — must be a new instance 93 $writerAfter = self::getInaccessibleProperty($handler, 'callWriter'); 94 $this->assertNotSame($writerBefore, $writerAfter); 95 $this->assertInstanceOf(\dokuwiki\Parsing\Handler\CallWriter::class, $writerAfter); 96 } 97 98 /** 99 * Regression test for #4637 100 * 101 * handleToken() must route plugin_* modes through plugin() even when 102 * the same name is also registered as a mode object. 103 * 104 * Before the fix, modeObjects was consulted first, which called 105 * SyntaxPlugin::handle() directly. That returns data but never 106 * emits an instruction via addPluginCall(), so the plugin's rendered 107 * output silently disappeared. 108 */ 109 function testPluginModeIsRoutedThroughPluginHandler() 110 { 111 $handler = new Handler(new ModeRegistry('dw')); 112 113 // Plugins register themselves as mode objects under their plugin_* name. 114 // This reproduces the conflict the bug depended on. 115 $info = plugin_load('syntax', 'info'); 116 $this->assertNotNull($info, 'info plugin must be available for this test'); 117 $handler->registerModeObject('plugin_info', $info); 118 119 $handler->handleToken('plugin_info', '~~INFO:datetime~~', DOKU_LEXER_SPECIAL, 0); 120 121 // After the fix, plugin() runs and emits a plugin instruction. 122 // With the bug, modeObjects['plugin_info']->handle() ran and emitted nothing. 123 $this->assertCount(1, $handler->calls, 'plugin mode must emit exactly one instruction'); 124 [$name, $args] = $handler->calls[0]; 125 $this->assertSame('plugin', $name); 126 $this->assertSame('info', $args[0]); 127 $this->assertSame(['datetime'], $args[1]); 128 $this->assertSame('~~INFO:datetime~~', $args[3]); 129 } 130} 131