xref: /dokuwiki/_test/tests/Parsing/HandlerTest.php (revision 47a02a102092be9e1e6f1ddaf158bdfffdb13d4f)
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