xref: /dokuwiki/_test/tests/Parsing/HandlerTest.php (revision 36ba8eadc205a4e1af5099c74b747e2256faadd4)
1<?php
2
3namespace dokuwiki\test\Parsing;
4
5use dokuwiki\Parsing\Handler;
6use dokuwiki\Parsing\ParserMode\ModeInterface;
7
8class HandlerTest extends \DokuWikiTest
9{
10    function testGetModeNameReturnsOriginalName()
11    {
12        $handler = new Handler();
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();
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    /**
56     * Regression test for #4637
57     *
58     * handleToken() must route plugin_* modes through plugin() even when
59     * the same name is also registered as a mode object.
60     *
61     * Before the fix, modeObjects was consulted first, which called
62     * SyntaxPlugin::handle() directly. That returns data but never
63     * emits an instruction via addPluginCall(), so the plugin's rendered
64     * output silently disappeared.
65     */
66    function testPluginModeIsRoutedThroughPluginHandler()
67    {
68        $handler = new Handler();
69
70        // Plugins register themselves as mode objects under their plugin_* name.
71        // This reproduces the conflict the bug depended on.
72        $info = plugin_load('syntax', 'info');
73        $this->assertNotNull($info, 'info plugin must be available for this test');
74        $handler->registerModeObject('plugin_info', $info);
75
76        $handler->handleToken('plugin_info', '~~INFO:datetime~~', DOKU_LEXER_SPECIAL, 0);
77
78        // After the fix, plugin() runs and emits a plugin instruction.
79        // With the bug, modeObjects['plugin_info']->handle() ran and emitted nothing.
80        $this->assertCount(1, $handler->calls, 'plugin mode must emit exactly one instruction');
81        [$name, $args] = $handler->calls[0];
82        $this->assertSame('plugin', $name);
83        $this->assertSame('info', $args[0]);
84        $this->assertSame(['datetime'], $args[1]);
85        $this->assertSame('~~INFO:datetime~~', $args[3]);
86    }
87}
88