1<?php 2 3use DOMWrap\Document; 4 5require_once DOKU_INC . 'inc/parser/xhtml.php'; 6 7/** 8 * @group plugin_indexmenu 9 */ 10class IndexmenuSyntaxTest extends DokuWikiTest 11{ 12 13 public function setup(): void 14 { 15// global $conf; 16 $this->pluginsEnabled[] = 'indexmenu'; 17 parent::setup(); 18 19 //$conf['plugin']['indexmenu']['headpage'] = ''; 20 //$conf['plugin']['indexmenu']['hide_headpage'] = false; 21 22 //saveWikiText('titleonly:sub:test', "====== Title ====== \n content", 'created'); 23 //saveWikiText('test', "====== Title ====== \n content", 'created'); 24 //idx_addPage('titleonly:sub:test'); 25 //idx_addPage('test'); 26 } 27 28// public function __construct() { 29//// $this->exampleIndex = "{{indexmenu>:}}"; 30// 31// parent::__construct(); 32// } 33 34 /** 35 * Create from list of values the output array of handle() 36 * 37 * @param array $values 38 * @return array aligned similar to output of handle() 39 */ 40 private function createData($values) 41 { 42 43 [ 44 $ns, $theme, $identifier, $nocookie, $navbar, $noscroll, $maxjs, $notoc, $jsajax, $context, $nomenu, 45 $sort, $msort, $rsort, $nsort, $level, $nons, $nopg, $subnss, $max, $maxAjax, $js, $skipns, $skipfile, 46 $skipnscombined, $skipfilecombined, $hsort, $headpage, $hide_headpage, $jsVersion 47 ] = $values; 48 49 return [ 50 $ns, 51 [ 52 'theme' => $theme, 53 'identifier' => $identifier, 54 'nocookie' => $nocookie, 55 'navbar' => $navbar, 56 'noscroll' => $noscroll, 57 'maxJs' => $maxjs, 58 'notoc' => $notoc, 59 'jsAjax' => $jsajax, 60 'context' => $context, 61 'nomenu' => $nomenu, 62 ], 63 [ 64 'sort' => $sort, 65 'msort' => $msort, 66 'rsort' => $rsort, 67 'nsort' => $nsort, 68 'hsort' => $hsort, 69 ], 70 [ 71 'level' => $level, 72 'nons' => $nons, 73 'nopg' => $nopg, 74 'subnss' => $subnss, 75 'max' => $max, 76 'js' => $js, 77 'skipns' => $skipns, 78 'skipfile' => $skipfile, 79 'skipnscombined' => $skipnscombined, 80 'skipfilecombined' => $skipfilecombined, 81 'headpage' => $headpage, 82 'hide_headpage' => $hide_headpage, 83 'maxajax' => $maxAjax, 84 'navbar' => $navbar, 85 'theme' => $theme 86 ], 87 $jsVersion 88 ]; 89 } 90 91 /** 92 * Data provider 93 * 94 * @return array[] 95 */ 96 public static function someSyntaxes() 97 { 98 return [ 99 //root ns (empty is not recognized..) 100 // [syntax, data] 101 [ 102 "{{indexmenu>:}}", 103 [ 104 '', 'default', 'random', false, false, false, 1, false, '', false, false, 105 0, false, false, false, -1, false, false, [], 0, 1, false, '', '', [''], [''], false, 106 ":start:,:same:,:inside:", 1, 1 107 ] 108 ], 109 //root ns, #levels=1, js renderer 110 [ 111 "{{indexmenu>#1|js}}", 112 [ 113 '', 'default', 'random', false, false, false, 1, false, '', false, false, 114 0, false, false, false, 1, false, false, [], 0, 1, true, '', '', [''], [''], false, 115 ":start:,:same:,:inside:", 1, 1 116 ] 117 ], 118 //root ns, #levels=2, all not js specific options (nocookie is from context) 119 [ 120 "{{indexmenu>#2 test#6|navbar context tsort dsort msort hsort rsort nsort nons nopg}}", 121 [ 122 '', 'default', 'random', true, true, false, 1, false, '&sort=t&msort=indexmenu_n&rsort=1&nsort=1&hsort=1&nopg=1', true, false, 123 't', 'indexmenu_n', true, true, 2, true, true, [['test', 6]], 0, 1, false, '', '', [''], [''], true, 124 ":start:,:same:,:inside:", 1, 1 125 ] 126 ], 127 //root ns, #levels=2, js renderer, all not js specific options 128 [ 129 "{{indexmenu>#2 test#6|navbar js#bj_ubuntu.png context tsort dsort msort hsort rsort nsort nons nopg}}", 130 [ 131 '', 'bj_ubuntu.png', 'random', true, true, false, 1, false, '&sort=t&msort=indexmenu_n&rsort=1&nsort=1&hsort=1&nopg=1', true, false, 132 't', 'indexmenu_n', true, true, 2, true, true, [['test', 6]], 0, 1, true, '', '', [''], [''], true, 133 ":start:,:same:,:inside:", 1, 1 134 ] 135 ], 136 //root ns, #levels=1, all options 137 [ 138 "{{indexmenu>#1|navbar context nocookie noscroll notoc nomenu dsort msort#date:modified hsort rsort nsort nons nopg max#2#4 maxjs#3 id#54321}}", 139 [ 140 '', 'default', 'random', true, true, true, 1, true, '&sort=d&msort=date modified&rsort=1&nsort=1&hsort=1&nopg=1', true, true, 141 'd', 'date modified', true, true, 1, true, true, [], 0, 1, false, '', '', [''], [''], true, 142 ":start:,:same:,:inside:", 1, 1 143 ] 144 ], 145 //root ns, #levels=1, js renderer, all options 146 [ 147 "{{indexmenu>#1|js#bj_ubuntu.png navbar context nocookie noscroll notoc nomenu dsort msort#date:modified hsort rsort nsort nons nopg max#2#4 maxjs#3 id#54321}}", 148 [ 149 '', 'bj_ubuntu.png', 54321, true, true, true, 3, true, '&sort=d&msort=date modified&rsort=1&nsort=1&hsort=1&nopg=1&max=4', true, true, 150 'd', 'date modified', true, true, 1, true, true, [], 2, 4, true, '', '', [''], [''], true, 151 ":start:,:same:,:inside:", 1, 1 152 ] 153 ], 154 //root ns, #levels=1, skipfile and ns 155 156 [ 157 "{{indexmenu>#1 test|skipfile+/(^myusers:spaces$|privatens:userss)/ skipns=/(^myusers:spaces$|privatens:users)/ id#ns}}", 158 [ 159 '', 'default', 'random', false, false, false, 1, false, '&skipns=%3D/%28%5Emyusers%3Aspaces%24%7Cprivatens%3Ausers%29/&skipfile=%2B/%28%5Emyusers%3Aspaces%24%7Cprivatens%3Auserss%29/', false, false, 160 0, false, false, false, 1, false, false, [['test', -1]], 0, 1, false, '=/(^myusers:spaces$|privatens:users)/', 161 '+/(^myusers:spaces$|privatens:userss)/', ['/(^myusers:spaces$|privatens:users)/'], ['', '/(^myusers:spaces$|privatens:userss)/'], false, 162 ":start:,:same:,:inside:", 1, 1 163 ] 164 ], 165 //root ns, #levels=1, js renderer, skipfile and ns 166 [ 167 "{{indexmenu>#1 test|js skipfile=/(^myusers:spaces$|privatens:userss)/ skipns+/(^myusers:spaces$|privatens:userssss)/ id#ns}}", 168 [ 169 '', 'default', 0, false, false, false, 1, false, '&skipns=%2B/%28%5Emyusers%3Aspaces%24%7Cprivatens%3Auserssss%29/&skipfile=%3D/%28%5Emyusers%3Aspaces%24%7Cprivatens%3Auserss%29/', false, false, 170 0, false, false, false, 1, false, false, [['test', -1]], 0, 1, true, '+/(^myusers:spaces$|privatens:userssss)/', 171 '=/(^myusers:spaces$|privatens:userss)/', ['', '/(^myusers:spaces$|privatens:userssss)/'], ['/(^myusers:spaces$|privatens:userss)/'], false, 172 ":start:,:same:,:inside:", 1, 1 173 ] 174 ] 175 ]; 176 } 177 178 /** 179 * Parse the syntax to options 180 * expect: different combinations with or without js option, covers recognizing all syntax options 181 * 182 * @dataProvider someSyntaxes 183 */ 184 public function testHandle($syntax, $changedData) 185 { 186 $plugin = new syntax_plugin_indexmenu_indexmenu(); 187 188 $null = new Doku_Handler(); 189 $result = $plugin->handle($syntax, 0, 40, $null); 190 191 //copy unique generated number, which is about 23 characters 192 $len_id = strlen($result[1]['identifier']); 193 if (!is_numeric($changedData[2]) && ($len_id > 18 && $len_id <= 23)) { 194 $changedData[2] = $result[1]['identifier']; 195 } 196 $data = $this->createData($changedData); 197 198 $this->assertEquals($data, $result, 'Data array corrupted'); 199 } 200 201 202 /** 203 * Data provider 204 * 205 * @return array[] 206 */ 207 public static function differentNSs() 208 { 209 $pageInRoot = 'page'; 210 $pageInLvl1 = 'ns:page'; 211 $pageInLvl2 = 'ns1:ns2:page'; 212 return [ 213 //indexmenu on page at root level 214 ['{{indexmenu>|}}', '', [], $pageInRoot], 215 ['{{indexmenu>#1}}', '', [], $pageInRoot], 216 ['{{indexmenu>:}}', '', [], $pageInRoot], 217 ['{{indexmenu>.}}', '', [], $pageInRoot], 218 ['{{indexmenu>.:}}', '', [], $pageInRoot], 219 ['{{indexmenu>..}}', '', [], $pageInRoot], 220 ['{{indexmenu>..:}}', '', [], $pageInRoot], 221 ['{{indexmenu>myns}}', 'myns', [], $pageInRoot], 222 ['{{indexmenu>:myns}}', 'myns', [], $pageInRoot], 223 ['{{indexmenu>.myns}}', 'myns', [], $pageInRoot], 224 ['{{indexmenu>.:myns}}', 'myns', [], $pageInRoot], 225 ['{{indexmenu>..myns}}', 'myns', [], $pageInRoot], 226 ['{{indexmenu>..:myns}}', 'myns', [], $pageInRoot], 227 228 //indexmenu on page in a namespace 229 ['{{indexmenu>|}}', '', [], $pageInLvl1], 230 ['{{indexmenu>#1}}', '', [], $pageInLvl1], 231 ['{{indexmenu>:}}', '', [], $pageInLvl1], 232 ['{{indexmenu>.}}', 'ns', [], $pageInLvl1], 233 ['{{indexmenu>.:}}', 'ns', [], $pageInLvl1], 234 ['{{indexmenu>..}}', '', [], $pageInLvl1], 235 ['{{indexmenu>..:}}', '', [], $pageInLvl1], 236 ['{{indexmenu>myns}}', 'myns', [], $pageInLvl1], //was ns:myns 237 ['{{indexmenu>:myns}}', 'myns', [], $pageInLvl1], 238 ['{{indexmenu>.myns}}', 'ns:myns', [], $pageInLvl1], 239 ['{{indexmenu>.:myns}}', 'ns:myns', [], $pageInLvl1], 240 ['{{indexmenu>..myns}}', 'myns', [], $pageInLvl1], 241 ['{{indexmenu>..:myns}}', 'myns', [], $pageInLvl1], 242 ['{{indexmenu>myns:myns}}', 'myns:myns', [], $pageInLvl2], 243 244 //indexmenu on page in a namespace 245 ['{{indexmenu>|}}', '', [], $pageInLvl2], 246 ['{{indexmenu>#1}}', '', [], $pageInLvl2], 247 ['{{indexmenu>:}}', '', [], $pageInLvl2], 248 ['{{indexmenu>.}}', 'ns1:ns2', [], $pageInLvl2], 249 ['{{indexmenu>.:}}', 'ns1:ns2', [], $pageInLvl2], 250 ['{{indexmenu>..}}', '', [], $pageInLvl2], //strange indexmenu specific exception! TODO remove? 251 ['{{indexmenu>..:}}', 'ns1', [], $pageInLvl2], 252 ['{{indexmenu>myns}}', 'myns', [], $pageInLvl2], //was ns1:ns2:myns 253 ['{{indexmenu>:myns}}', 'myns', [], $pageInLvl2], 254 ['{{indexmenu>.myns}}', 'ns1:ns2:myns', [], $pageInLvl2], 255 ['{{indexmenu>.:myns}}', 'ns1:ns2:myns', [], $pageInLvl2], 256 ['{{indexmenu>..myns}}', 'ns1:myns', [], $pageInLvl2], 257 ['{{indexmenu>..:myns}}', 'ns1:myns', [], $pageInLvl2], 258 ['{{indexmenu>myns:myns}}', 'myns:myns', [], $pageInLvl2], 259 260 ['{{indexmenu>..:..:myns}}', 'ns1:myns', [], 'ns1:ns2:ns3:page'], 261 ['{{indexmenu>0}}', '0', [], 'ns1:page'], //was ns1:0 262 263 //indexmenu on page at root level and subns 264 ['{{indexmenu> #1|}}', '', [], $pageInLvl2], //no subns, spaces before are removed 265 ['{{indexmenu>#1 #1}}', '', [['', 1]], $pageInLvl2], 266 ['{{indexmenu>: :}}', '', [['', -1]], $pageInLvl2], 267 ['{{indexmenu>. .}}', 'ns1:ns2', [['ns1:ns2', -1]], $pageInLvl2], 268 ['{{indexmenu>.: .:}}', 'ns1:ns2', [['ns1:ns2', -1]], $pageInLvl2], 269 ['{{indexmenu>.. ..}}', '', [['', -1]], $pageInLvl2], 270 ['{{indexmenu>..: ..:}}', 'ns1', [['ns1', -1]], $pageInLvl2], 271 ['{{indexmenu>myns myns}}', 'myns', [['myns', -1]], $pageInLvl2], //was ns1:ns2:myns 272 ['{{indexmenu>:myns :myns}}', 'myns', [['myns', -1]], $pageInLvl2], 273 ['{{indexmenu>.myns .myns}}', 'ns1:ns2:myns', [['ns1:ns2:myns', -1]], $pageInLvl2], 274 ['{{indexmenu>.:myns .:myns}}', 'ns1:ns2:myns', [['ns1:ns2:myns', -1]], $pageInLvl2], 275 ['{{indexmenu>..myns ..myns}}', 'ns1:myns', [['ns1:myns', -1]], $pageInLvl2], 276 ['{{indexmenu>..:myns ..myns}}', 'ns1:myns', [['ns1:myns', -1]], $pageInLvl2], 277 ['{{indexmenu>myns:myns myns:myns}}', 'myns:myns', [['myns:myns', -1]], $pageInLvl2], 278 279 //indexmenu on page in a namespace 280 ['{{indexmenu>|}}', '', [], $pageInLvl2], 281 ['{{indexmenu>#1}}', '', [], $pageInLvl2], 282 ['{{indexmenu>:}}', '', [], $pageInLvl2], 283 ['{{indexmenu>.}}', 'ns1:ns2', [], $pageInLvl2], 284 ['{{indexmenu>.:}}', 'ns1:ns2', [], $pageInLvl2], 285 ['{{indexmenu>..}}', '', [], $pageInLvl2], //strange indexmenu specific exception! TODO remove? 286 ['{{indexmenu>..:}}', 'ns1', [], $pageInLvl2], 287 ['{{indexmenu>myns:}}', 'myns', [], $pageInLvl2], //was ns1:ns2:myns 288 ['{{indexmenu>:myns:}}', 'myns', [], $pageInLvl2], 289 ['{{indexmenu>.myns:}}', 'ns1:ns2:myns', [], $pageInLvl2], 290 ['{{indexmenu>.:myns:}}', 'ns1:ns2:myns', [], $pageInLvl2], 291 ['{{indexmenu>..myns:}}', 'ns1:myns', [], $pageInLvl2], 292 ['{{indexmenu>..:myns:}}', 'ns1:myns', [], $pageInLvl2], 293 ['{{indexmenu>myns:myns:}}', 'myns:myns', [], $pageInLvl2], 294 ]; 295 } 296 297 /** 298 * Parse the syntax to options 299 * expect: different combinations with or without js option, covers recognizing all syntax options 300 * 301 * @dataProvider differentNSs 302 */ 303 public function testResolving($syntax, $expectedNs, $expectedSubNss, $pageWithIndexmenu) 304 { 305 global $ID; 306 $ID = $pageWithIndexmenu; 307 308 $plugin = new syntax_plugin_indexmenu_indexmenu(); 309 310 $null = new Doku_Handler(); 311 $result = $plugin->handle($syntax, 0, 40, $null); 312 313 $this->assertEquals($expectedNs, $result[0], 'check resolved ns'); 314 $this->assertEquals($expectedSubNss, $result[3]['subnss'], 'check resolved subNSs'); 315 } 316 317 /** 318 * Rendering for nonexisting namespace 319 * expect: no paragraph due to no message set 320 * expect: one paragraph, since message set 321 * expect: contains namespace which replaced {{ns}} 322 * expect: message contained rendered italic syntax 323 */ 324 public function testRenderEmptymsg() 325 { 326 global $conf; 327 328 $noexistns = 'nonexisting:namespace'; 329 $emptyindexsyntax = "{{indexmenu>$noexistns}}"; 330 331 $xhtml = new Doku_Renderer_xhtml(); 332 $plugin = new syntax_plugin_indexmenu_indexmenu(); 333 334 $null = new Doku_Handler(); 335 $result = $plugin->handle($emptyindexsyntax, 0, 10, $null); 336 337 //no empty message 338 $plugin->render('xhtml', $xhtml, $result); 339 340 $doc = (new Document())->html($xhtml->doc); 341 $this->assertEquals(0, $doc->find('p')->count()); 342 343 // Fill in empty message 344 $conf['plugin']['indexmenu']['empty_msg'] = 'This namespace is //empty//: {{ns}}'; 345 $plugin->render('xhtml', $xhtml, $result); 346 $doc = (new Document())->html($xhtml->doc); 347 348 $this->assertEquals(1, $doc->find('p')->count()); 349// $this->assertEquals(1, $doc->find("p:contains($noexistns)")->count()); 350 $this->assertEquals(1, $doc->find("p em")->count()); 351 } 352 353} 354