1<?php 2require_once(__DIR__ . '/../lib/grammar.php'); 3require_once(__DIR__ . '/../lib/exceptions.php'); 4 5/** 6 * General tests for the ifauthex plugin 7 * 8 * @group plugin_ifauthex 9 * @group plugins 10 */ 11class general_plugin_ifauthex_test extends DokuWikiTest 12{ 13 14 protected $pluginsEnabled = array('ifauthex'); 15 16 const VALID_EXPRESSIONS = array( 17 'user', 18 '"user name"', 19 'user-name', 20 'user.name', 21 '"user \\ name \\" surname"', 22 '!user', 23 '@group', 24 '!@group', 25 '!(!@group && !@group && !@group)', 26 '!(!@group && !user && @group) || !(@group || user || @group)', 27 '!(!@group && @group || !user) && (!user || user && @group)', 28 '!(!@group && user) && !(!@group || @group || user)', 29 '!(!@group || !user && !user) || !(user || @group || !@group)', 30 '!(!@group || @group || !@group) && (@group || @group && !@group)', 31 '!(!@group || user || user) && !(!user || !user || !user)', 32 '!(!user && !@group) || (!@group || !user && @group)', 33 '!(!user && @group && @group) && (user || !@group || user)', 34 '!(!user && user || !user) && !(@group || !@group && user)', 35 '!(!user || !@group || user) || (!user || !@group && !@group)', 36 '!(!user || @group && !user) || !(!@group && user || !user)', 37 '!(!user || user || !@group) && !(user && user && !user)', 38 '!(@group && !@group || !user) || (@group && @group || user)', 39 '!(@group && !user) || !(!user && @group && user)', 40 '!(@group && user && @group) && (!@group && !user)', 41 '!(@group || !@group || !@group) || (user && !user || !user)', 42 '!(@group || !user || user) || !(@group && !user && !user)', 43 '!(@group || user && !user) && (!user && !@group || @group)', 44 '!(user && !@group && user) && !(!@group && !@group && @group)', 45 '!(user && !user || !user) || !(@group)', 46 '!(user && @group) && (!user || user || !user)', 47 '!(user || !@group && @group) && !(!@group || user && !user)', 48 '!(user || !user || !@group) || !(user || @group || user)', 49 '!(user || @group || user) && (@group || @group && user)', 50 '!user || !user || user', 51 '(!@group && !user && @group) || !(@group || !user || !user)', 52 '(!@group && @group || !user) && (!user || !user && !user)', 53 '(!@group && user) && !(!@group || !@group || @group)', 54 '(!@group || !user && !user) || !(user || !@group && user)', 55 '(!@group || @group || !@group) && (@group && user)', 56 '(!@group || user || user) && !(!user && user || !@group)', 57 '(!user && !@group) || (!@group && user && !user)', 58 '(!user && @group && @group) && (user && @group || @group)', 59 '(!user && user || !user) && !(@group && @group && @group)', 60 '(!user || !@group || user) || (!user && !user)', 61 '(!user || @group && !user) || !(!@group && !user || !@group)', 62 '(!user || user || !@group) && !(user && !user && !@group)', 63 '(@group && !@group || !user) || (@group && !@group || @group)', 64 '(@group && !user) || !(!user && !@group && @group)', 65 '(@group && user && @group) && !(user || user)', 66 '(@group || !@group || !@group) || (@group || user || !user)', 67 '(@group || !user || user) || !(!user || user && !user)', 68 '(@group || user && !user) && (!@group || @group || @group)', 69 '(user && !@group && @group) || (user || @group && user)', 70 '(user && !user || !user) || !(@group || !user)', 71 '(user && @group) && (!user || !user || !@group)', 72 '(user || !@group && @group) && !(!@group || !user && !@group)', 73 '(user || !user || !@group) || !(user || !@group || @group)', 74 '(user || @group || user) && (@group || !@group && @group)', 75 'user && user || @group' 76 ); 77 78 const VALID_MB_EXPRESSIONS = array( 79 "\u{7D4C}\u{55B6}\u{4F01}\u{753B}\u{672C}\u{90E8}", 80 "\u{7D4C}\u{55B6}\u{4F01} && \u{753B}\u{672C}\u{90E8}", 81 "\u{7D4C}\u{55B6}\u{4F01} && \u{753B} || @\u{672C}\u{90E8}", 82 "!@\u{7D4C} || (\u{55B6}\u{4F01} && \u{753B} || @\u{672C}) && !\u{90E8}" 83 ); 84 85 const UNKNOWN_TOKEN_EXPRESSIONS = array( 86 '!(!@group & !@group && !@group)', 87 '!(!@group && !user && @group) | !(@group || user || @group)', 88 '!(!@group && @group || !user] && (!user || user && @group)', 89 '!(!@group && user) && !^!@group || @group || user)', 90 '!(!@group || <inject> !user && !user) || !(user || @group || !@group)', 91 '!(!@group || @group {--} !@group) && (@group || @group && !@group)', 92 '!(!@group || user || user) && !(!user || > !user || !user)', 93 '!(!user && !@group) <|| (!@group || !user && @group)', 94 '!(!user && @group && @group) / && (user || !@group || user)', 95 '!(!user && user || : !user) && !(@group || !@group && user)', 96 '"user name\\"', 97 '"user name\\\\\\"' 98 ); 99 100 const STRAY_TOKEN_EXPRESSIONS = array( 101 'usr usr2', 102 'user && @group) && (!user || !user || !@group)', 103 // Closed brackets alone are unmatched: 104 '@group && (usr) @another', 105 '(user || !user || !@group) || !user || !@group || @group)', 106 ); 107 108 const UNMATCHED_WRAPPER_EXPRESSIONS = array( 109 '(user || !@group && @group && !(!@group || !user && !@group)', 110 '(user || @group || user) && (@group || !@group && @group' 111 ); 112 113 const NOT_ENOUGH_ARGS_EXPRESSIONS = array( 114 '!(@group && user && @group) && (!@group && !)', 115 '!(@group || !@group || !@group) || (user &&)', 116 '!(@group || !user ||) || !(@)', 117 '!(@group || user && !user) && @', 118 '!(@group || user && !user) ||', 119 '@!usr', // @ takes "!", but when ! is parsed, no arg is left 120 '@@group', // @ takes "@", but when ! is parsed, no arg is left 121 ); 122 123 const MALFORMED_EXPRESSIONS = array( 124 'usr usr2', // More than one element in root 125 '()', // Subexpression must have one root 126 '(usr usr2)', 127 '@()', // Group takes exactly a literal 128 '@(group)' 129 ); 130 131 public static function strip($txt) { 132 return preg_replace('/\s/', '', $txt); 133 } 134 135 public function test_parse() 136 { 137 foreach (self::VALID_EXPRESSIONS as $expr) { 138 $failureMsg = 'Assertion failed at expression "' . $expr . '".'; 139 $ast = null; 140 $rebuiltExpr = null; 141 $this->assertNotNull($ast = auth_expr_parse($expr)); 142 $this->assertNotNull($rebuiltExpr = $ast->getRepresentation()); 143 $this->assertEquals(self::strip($rebuiltExpr), self::strip($expr)); 144 } 145 if (\AST\TokenDefinition::supportsMultibyte()) { 146 foreach (self::VALID_MB_EXPRESSIONS as $expr) { 147 $failureMsg = 'Assertion failed at expression "' . $expr . '".'; 148 $ast = null; 149 $rebuiltExpr = null; 150 $this->assertNotNull($ast = auth_expr_parse($expr)); 151 $this->assertNotNull($rebuiltExpr = $ast->getRepresentation()); 152 $this->assertEquals(self::strip($rebuiltExpr), self::strip($expr)); 153 } 154 } 155 } 156 157 public function test_unknown_token() 158 { 159 foreach (self::UNKNOWN_TOKEN_EXPRESSIONS as $expr) { 160 $exc = null; 161 try { 162 auth_expr_parse($expr); 163 } catch (Exception $e) { 164 $exc = $e; 165 } 166 $this->assertInstanceOf(\AST\UnknownTokenException::class, $exc); 167 } 168 } 169 170 public function test_unmatched_wrappers() 171 { 172 foreach (self::UNMATCHED_WRAPPER_EXPRESSIONS as $expr) { 173 $exc = null; 174 try { 175 auth_expr_parse($expr); 176 } catch (Exception $e) { 177 $exc = $e; 178 } 179 $this->assertInstanceOf(\AST\UnmatchedWrapperException::class, $exc); 180 } 181 } 182 183 184 public function test_not_enough_args() 185 { 186 foreach (self::NOT_ENOUGH_ARGS_EXPRESSIONS as $expr) { 187 $exc = null; 188 try { 189 auth_expr_parse($expr); 190 } catch (Exception $e) { 191 $exc = $e; 192 } 193 $this->assertInstanceOf(\AST\NotEnoughArgumentsException::class, $exc); 194 } 195 } 196 197 public function test_malformed() 198 { 199 foreach (self::MALFORMED_EXPRESSIONS as $expr) { 200 $exc = null; 201 try { 202 $ast = null; 203 // The expression must parse, but not validate 204 $this->assertNotNull($ast = auth_expr_parse($expr)); 205 $ast->ensureWellFormed(); 206 } catch (Exception $e) { 207 $exc = $e; 208 } 209 $this->assertInstanceOf(\AST\MalformedExpressionException::class, $exc); 210 } 211 } 212 213 public function test_empty_parentehses() { 214 // This must not throw. It's malformed, but it's parsed correctly. 215 $this->assertNotNull(auth_expr_parse('()')); 216 } 217 218 public function test_empty() { 219 // This must not throw. It's malformed, but it's parsed correctly. 220 $this->assertNotNull(auth_expr_parse('')); 221 } 222 223 224 public function test_depth_limit() 225 { 226 $depthLimit = \AST\parse_config()->EXPR_DEPTH_LIMIT; 227 $this->expectException(RuntimeException::class); 228 auth_expr_parse(str_repeat('(', $depthLimit) . 'a && b' . str_repeat(')', $depthLimit)); 229 } 230 231 public function test_output() { 232 $info = array(); 233 $instructions = p_get_instructions('<ifauth (nonexistent)>hideme</ifauth><ifauth !(nonexistent)>showme</ifauth>'); 234 $xhtml = p_render('xhtml', $instructions, $info); 235 $this->assertTrue(stristr($xhtml, 'showme') !== false); 236 $this->assertTrue(stristr($xhtml, 'hideme') === false); 237 238 auth_expr_evaluation_context()->SIMULATE_USERS = array('nonexistent'); 239 $xhtml = p_render('xhtml', $instructions, $info); 240 $this->assertTrue(stristr($xhtml, 'showme') === false); 241 $this->assertTrue(stristr($xhtml, 'hideme') !== false); 242 auth_expr_evaluation_context()->SIMULATE_USERS = null; 243 } 244 245 public function test_operators() { 246 auth_expr_evaluation_context()->SIMULATE_IN_GROUPS = array('group'); 247 auth_expr_evaluation_context()->SIMULATE_USERS = array('user'); 248 249 $this->assertTrue(auth_expr_parse('user')->evaluate()); 250 $this->assertFalse(auth_expr_parse('!user')->evaluate()); 251 $this->assertTrue(auth_expr_parse('!user2')->evaluate()); 252 $this->assertFalse(auth_expr_parse('user2')->evaluate()); 253 $this->assertTrue(auth_expr_parse('@group')->evaluate()); 254 $this->assertFalse(auth_expr_parse('!@group')->evaluate()); 255 $this->assertTrue(auth_expr_parse('!@group2')->evaluate()); 256 $this->assertFalse(auth_expr_parse('@group2')->evaluate()); 257 258 $this->assertTrue(auth_expr_parse('user || @group')->evaluate()); 259 $this->assertTrue(auth_expr_parse('user || !@group')->evaluate()); 260 $this->assertTrue(auth_expr_parse('!user || @group')->evaluate()); 261 $this->assertFalse(auth_expr_parse('!user || !@group')->evaluate()); 262 $this->assertFalse(auth_expr_parse('user2 || @group2')->evaluate()); 263 $this->assertTrue(auth_expr_parse('user || @group2')->evaluate()); 264 $this->assertTrue(auth_expr_parse('user2 || @group')->evaluate()); 265 266 $this->assertTrue(auth_expr_parse('user && @group')->evaluate()); 267 $this->assertFalse(auth_expr_parse('user && !@group')->evaluate()); 268 $this->assertFalse(auth_expr_parse('!user && @group')->evaluate()); 269 $this->assertFalse(auth_expr_parse('!user && !@group')->evaluate()); 270 $this->assertFalse(auth_expr_parse('user2 && @group2')->evaluate()); 271 $this->assertFalse(auth_expr_parse('user && @group2')->evaluate()); 272 $this->assertFalse(auth_expr_parse('user2 && @group')->evaluate()); 273 274 $this->assertTrue(auth_expr_parse('(user || @group)')->evaluate()); 275 $this->assertTrue(auth_expr_parse('(user || !@group)')->evaluate()); 276 $this->assertTrue(auth_expr_parse('(!user || @group)')->evaluate()); 277 $this->assertFalse(auth_expr_parse('(!user || !@group)')->evaluate()); 278 $this->assertFalse(auth_expr_parse('(user2 || @group2)')->evaluate()); 279 $this->assertTrue(auth_expr_parse('(user || @group2)')->evaluate()); 280 $this->assertTrue(auth_expr_parse('(user2 || @group)')->evaluate()); 281 282 $this->assertFalse(auth_expr_parse('!(user || @group)')->evaluate()); 283 $this->assertFalse(auth_expr_parse('!(user || !@group)')->evaluate()); 284 $this->assertFalse(auth_expr_parse('!(!user || @group)')->evaluate()); 285 $this->assertTrue(auth_expr_parse('!(!user || !@group)')->evaluate()); 286 $this->assertTrue(auth_expr_parse('!(user2 || @group2)')->evaluate()); 287 $this->assertFalse(auth_expr_parse('!(user || @group2)')->evaluate()); 288 $this->assertFalse(auth_expr_parse('!(user2 || @group)')->evaluate()); 289 290 $this->assertTrue(auth_expr_parse('user, @group')->evaluate()); 291 $this->assertTrue(auth_expr_parse('user, !@group')->evaluate()); 292 $this->assertTrue(auth_expr_parse('!user, @group')->evaluate()); 293 $this->assertFalse(auth_expr_parse('!user, !@group')->evaluate()); 294 $this->assertFalse(auth_expr_parse('user2, @group2')->evaluate()); 295 $this->assertTrue(auth_expr_parse('user, @group2')->evaluate()); 296 $this->assertTrue(auth_expr_parse('user2, @group')->evaluate()); 297 298 auth_expr_evaluation_context()->SIMULATE_IN_GROUPS = null; 299 auth_expr_evaluation_context()->SIMULATE_USERS = null; 300 } 301 302 /** 303 * Simple test to make sure the plugin.info.txt is in correct format 304 */ 305 public function test_plugininfo() 306 { 307 $file = __DIR__ . '/../plugin.info.txt'; 308 $this->assertFileExists($file); 309 310 $info = confToHash($file); 311 312 $this->assertArrayHasKey('base', $info); 313 $this->assertArrayHasKey('author', $info); 314 $this->assertArrayHasKey('email', $info); 315 $this->assertArrayHasKey('date', $info); 316 $this->assertArrayHasKey('name', $info); 317 $this->assertArrayHasKey('desc', $info); 318 $this->assertArrayHasKey('url', $info); 319 320 $this->assertEquals('ifauthex', $info['base']); 321 $this->assertRegExp('/^https?:\/\//', $info['url']); 322 $this->assertTrue(mail_isvalid($info['email'])); 323 $this->assertRegExp('/^\d\d\d\d-\d\d-\d\d$/', $info['date']); 324 $this->assertTrue(false !== strtotime($info['date'])); 325 } 326 327 /** 328 * Test to ensure that every conf['...'] entry in conf/default.php has a corresponding meta['...'] entry in 329 * conf/metadata.php. 330 */ 331 public function test_plugin_conf() 332 { 333 $conf_file = __DIR__ . '/../conf/default.php'; 334 $meta_file = __DIR__ . '/../conf/metadata.php'; 335 336 if (!file_exists($conf_file) && !file_exists($meta_file)) { 337 self::markTestSkipped('No config files exist -> skipping test'); 338 } 339 340 if (file_exists($conf_file)) { 341 include($conf_file); 342 } 343 if (file_exists($meta_file)) { 344 include($meta_file); 345 } 346 347 $this->assertEquals( 348 gettype($conf), 349 gettype($meta), 350 'Both ' . DOKU_PLUGIN . 'ifauthex/conf/default.php and ' . DOKU_PLUGIN . 'ifauthex/conf/metadata.php have to exist and contain the same keys.' 351 ); 352 353 if ($conf !== null && $meta !== null) { 354 foreach ($conf as $key => $value) { 355 $this->assertArrayHasKey( 356 $key, 357 $meta, 358 'Key $meta[\'' . $key . '\'] missing in ' . DOKU_PLUGIN . 'ifauthex/conf/metadata.php' 359 ); 360 } 361 362 foreach ($meta as $key => $value) { 363 $this->assertArrayHasKey( 364 $key, 365 $conf, 366 'Key $conf[\'' . $key . '\'] missing in ' . DOKU_PLUGIN . 'ifauthex/conf/default.php' 367 ); 368 } 369 } 370 371 } 372} 373