Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Weblib tests. 19 * 20 * @package core 21 * @category phpunit 22 * @copyright © 2006 The Open University 23 * @author T.J.Hunt@open.ac.uk 24 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 25 */ 26 27 class weblib_test extends advanced_testcase { 28 29 /** 30 * @covers ::format_string 31 */ 32 public function test_format_string() { 33 global $CFG; 34 35 // Ampersands. 36 $this->assertSame("& &&&&& &&", format_string("& &&&&& &&")); 37 $this->assertSame("ANother & &&&&& Category", format_string("ANother & &&&&& Category")); 38 $this->assertSame("ANother & &&&&& Category", format_string("ANother & &&&&& Category", true)); 39 $this->assertSame("Nick's Test Site & Other things", format_string("Nick's Test Site & Other things", true)); 40 $this->assertSame("& < > \" '", format_string("& < > \" '", true, ['escape' => false])); 41 42 // String entities. 43 $this->assertSame(""", format_string(""")); 44 45 // Digital entities. 46 $this->assertSame("&11234;", format_string("&11234;")); 47 48 // Unicode entities. 49 $this->assertSame("ᅻ", format_string("ᅻ")); 50 51 // < and > signs. 52 $originalformatstringstriptags = $CFG->formatstringstriptags; 53 54 $CFG->formatstringstriptags = false; 55 $this->assertSame('x < 1', format_string('x < 1')); 56 $this->assertSame('x > 1', format_string('x > 1')); 57 $this->assertSame('x < 1 and x > 0', format_string('x < 1 and x > 0')); 58 59 $CFG->formatstringstriptags = true; 60 $this->assertSame('x < 1', format_string('x < 1')); 61 $this->assertSame('x > 1', format_string('x > 1')); 62 $this->assertSame('x < 1 and x > 0', format_string('x < 1 and x > 0')); 63 64 $CFG->formatstringstriptags = $originalformatstringstriptags; 65 } 66 67 /** 68 * The format string static caching should include the filters option to make 69 * sure filters are correctly applied when requested. 70 */ 71 public function test_format_string_static_caching_with_filters() { 72 global $CFG; 73 74 $this->resetAfterTest(true); 75 $this->setAdminUser(); 76 $generator = $this->getDataGenerator(); 77 $course = $generator->create_course(); 78 $user = $generator->create_user(); 79 $rawstring = '<span lang="en" class="multilang">English</span><span lang="ca" class="multilang">Catalan</span>'; 80 $expectednofilter = strip_tags($rawstring); 81 $expectedfilter = 'English'; 82 $striplinks = true; 83 $context = context_course::instance($course->id); 84 $options = [ 85 'context' => $context, 86 'escape' => true, 87 'filter' => false 88 ]; 89 90 $this->setUser($user); 91 92 // Format the string without filters. It should just strip the 93 // links. 94 $nofilterresult = format_string($rawstring, $striplinks, $options); 95 $this->assertEquals($expectednofilter, $nofilterresult); 96 97 // Add the multilang filter. Make sure it's enabled globally. 98 $CFG->filterall = true; 99 $CFG->stringfilters = 'multilang'; 100 filter_set_global_state('multilang', TEXTFILTER_ON); 101 filter_set_local_state('multilang', $context->id, TEXTFILTER_ON); 102 // This time we want to apply the filters. 103 $options['filter'] = true; 104 $filterresult = format_string($rawstring, $striplinks, $options); 105 $this->assertMatchesRegularExpression("/$expectedfilter/", $filterresult); 106 107 filter_set_local_state('multilang', $context->id, TEXTFILTER_OFF); 108 109 // Confirm that we get back the cached string. The result should be 110 // the same as the filtered text above even though we've disabled the 111 // multilang filter in between. 112 $cachedresult = format_string($rawstring, $striplinks, $options); 113 $this->assertMatchesRegularExpression("/$expectedfilter/", $cachedresult); 114 } 115 116 /** 117 * @covers ::s 118 */ 119 public function test_s() { 120 // Special cases. 121 $this->assertSame('0', s(0)); 122 $this->assertSame('0', s('0')); 123 $this->assertSame('0', s(false)); 124 $this->assertSame('', s(null)); 125 126 // Normal cases. 127 $this->assertSame('This Breaks " Strict', s('This Breaks " Strict')); 128 $this->assertSame('This Breaks <a>" Strict</a>', s('This Breaks <a>" Strict</a>')); 129 130 // Unicode characters. 131 $this->assertSame('Café', s('Café')); 132 $this->assertSame('一, 二, 三', s('一, 二, 三')); 133 134 // Don't escape already-escaped numeric entities. (Note, this behaviour 135 // may not be desirable. Perhaps we should remove these tests and that 136 // functionality, but we can only do that if we understand why it was added.) 137 $this->assertSame('An entity: ৿.', s('An entity: ৿.')); 138 $this->assertSame('An entity: б.', s('An entity: б.')); 139 $this->assertSame('An entity: &amp;.', s('An entity: &.')); 140 $this->assertSame('Not an entity: &amp;#x09ff;.', s('Not an entity: &#x09ff;.')); 141 142 // Test all ASCII characters (0-127). 143 for ($i = 0; $i <= 127; $i++) { 144 $character = chr($i); 145 $result = s($character); 146 switch ($character) { 147 case '"' : 148 $this->assertSame('"', $result); 149 break; 150 case '&' : 151 $this->assertSame('&', $result); 152 break; 153 case "'" : 154 $this->assertSame(''', $result); 155 break; 156 case '<' : 157 $this->assertSame('<', $result); 158 break; 159 case '>' : 160 $this->assertSame('>', $result); 161 break; 162 default: 163 $this->assertSame($character, $result); 164 break; 165 } 166 } 167 } 168 169 /** 170 * @covers ::format_text_email 171 */ 172 public function test_format_text_email() { 173 $this->assertSame("This is a TEST\n", 174 format_text_email('<p>This is a <strong>test</strong></p>', FORMAT_HTML)); 175 $this->assertSame("This is a TEST\n", 176 format_text_email('<p class="frogs">This is a <strong class=\'fishes\'>test</strong></p>', FORMAT_HTML)); 177 $this->assertSame('& so is this', 178 format_text_email('& so is this', FORMAT_HTML)); 179 $this->assertSame('Two bullets: ' . core_text::code2utf8(8226) . ' ' . core_text::code2utf8(8226), 180 format_text_email('Two bullets: • •', FORMAT_HTML)); 181 $this->assertSame(core_text::code2utf8(0x7fd2).core_text::code2utf8(0x7fd2), 182 format_text_email('習習', FORMAT_HTML)); 183 } 184 185 /** 186 * @covers ::obfuscate_email 187 */ 188 public function test_obfuscate_email() { 189 $email = 'some.user@example.com'; 190 $obfuscated = obfuscate_email($email); 191 $this->assertNotSame($email, $obfuscated); 192 $back = core_text::entities_to_utf8(urldecode($email), true); 193 $this->assertSame($email, $back); 194 } 195 196 /** 197 * @covers ::obfuscate_text 198 */ 199 public function test_obfuscate_text() { 200 $text = 'Žluťoučký koníček 32131'; 201 $obfuscated = obfuscate_text($text); 202 $this->assertNotSame($text, $obfuscated); 203 $back = core_text::entities_to_utf8($obfuscated, true); 204 $this->assertSame($text, $back); 205 } 206 207 /** 208 * @covers ::highlight 209 */ 210 public function test_highlight() { 211 $this->assertSame('This is <span class="highlight">good</span>', 212 highlight('good', 'This is good')); 213 214 $this->assertSame('<span class="highlight">span</span>', 215 highlight('SpaN', 'span')); 216 217 $this->assertSame('<span class="highlight">SpaN</span>', 218 highlight('span', 'SpaN')); 219 220 $this->assertSame('<span><span class="highlight">span</span></span>', 221 highlight('span', '<span>span</span>')); 222 223 $this->assertSame('He <span class="highlight">is</span> <span class="highlight">good</span>', 224 highlight('good is', 'He is good')); 225 226 $this->assertSame('This is <span class="highlight">good</span>', 227 highlight('+good', 'This is good')); 228 229 $this->assertSame('This is good', 230 highlight('-good', 'This is good')); 231 232 $this->assertSame('This is goodness', 233 highlight('+good', 'This is goodness')); 234 235 $this->assertSame('This is <span class="highlight">good</span>ness', 236 highlight('good', 'This is goodness')); 237 238 $this->assertSame('<p><b>test</b> <b>1</b></p><p><b>1</b></p>', 239 highlight('test 1', '<p>test 1</p><p>1</p>', false, '<b>', '</b>')); 240 241 $this->assertSame('<p><b>test</b> <b>1</b></p><p><b>1</b></p>', 242 highlight('test +1', '<p>test 1</p><p>1</p>', false, '<b>', '</b>')); 243 244 $this->assertSame('<p><b>test</b> 1</p><p>1</p>', 245 highlight('test -1', '<p>test 1</p><p>1</p>', false, '<b>', '</b>')); 246 } 247 248 /** 249 * @covers ::replace_ampersands_not_followed_by_entity 250 */ 251 public function test_replace_ampersands() { 252 $this->assertSame("This & that ", replace_ampersands_not_followed_by_entity("This & that ")); 253 $this->assertSame("This &nbsp that ", replace_ampersands_not_followed_by_entity("This   that ")); 254 } 255 256 /** 257 * @covers ::strip_links 258 */ 259 public function test_strip_links() { 260 $this->assertSame('this is a link', strip_links('this is a <a href="http://someaddress.com/query">link</a>')); 261 } 262 263 /** 264 * @covers ::wikify_links 265 */ 266 public function test_wikify_links() { 267 $this->assertSame('this is a link [ http://someaddress.com/query ]', wikify_links('this is a <a href="http://someaddress.com/query">link</a>')); 268 } 269 270 /** 271 * @covers ::clean_text 272 */ 273 public function test_clean_text() { 274 $text = "lala <applet>xx</applet>"; 275 $this->assertSame($text, clean_text($text, FORMAT_PLAIN)); 276 $this->assertSame('lala xx', clean_text($text, FORMAT_MARKDOWN)); 277 $this->assertSame('lala xx', clean_text($text, FORMAT_MOODLE)); 278 $this->assertSame('lala xx', clean_text($text, FORMAT_HTML)); 279 } 280 281 /** 282 * @covers ::qualified_me 283 */ 284 public function test_qualified_me() { 285 global $PAGE, $FULLME, $CFG; 286 $this->resetAfterTest(); 287 288 $PAGE = new moodle_page(); 289 290 $FULLME = $CFG->wwwroot.'/course/view.php?id=1&xx=yy'; 291 $this->assertSame($FULLME, qualified_me()); 292 293 $PAGE->set_url('/course/view.php', array('id'=>1)); 294 $this->assertSame($CFG->wwwroot.'/course/view.php?id=1', qualified_me()); 295 } 296 297 /** 298 * @covers \null_progress_trace 299 */ 300 public function test_null_progress_trace() { 301 $this->resetAfterTest(false); 302 303 $trace = new null_progress_trace(); 304 $trace->output('do'); 305 $trace->output('re', 1); 306 $trace->output('mi', 2); 307 $trace->finished(); 308 $output = ob_get_contents(); 309 $this->assertSame('', $output); 310 $this->expectOutputString(''); 311 } 312 313 /** 314 * @covers \null_progress_trace 315 */ 316 public function test_text_progress_trace() { 317 $this->resetAfterTest(false); 318 319 $trace = new text_progress_trace(); 320 $trace->output('do'); 321 $trace->output('re', 1); 322 $trace->output('mi', 2); 323 $trace->finished(); 324 $this->expectOutputString("do\n re\n mi\n"); 325 } 326 327 /** 328 * @covers \html_progress_trace 329 */ 330 public function test_html_progress_trace() { 331 $this->resetAfterTest(false); 332 333 $trace = new html_progress_trace(); 334 $trace->output('do'); 335 $trace->output('re', 1); 336 $trace->output('mi', 2); 337 $trace->finished(); 338 $this->expectOutputString("<p>do</p>\n<p>  re</p>\n<p>    mi</p>\n"); 339 } 340 341 /** 342 * @covers \html_list_progress_trace 343 */ 344 public function test_html_list_progress_trace() { 345 $this->resetAfterTest(false); 346 347 $trace = new html_list_progress_trace(); 348 $trace->output('do'); 349 $trace->output('re', 1); 350 $trace->output('mi', 2); 351 $trace->finished(); 352 $this->expectOutputString("<ul>\n<li>do<ul>\n<li>re<ul>\n<li>mi</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n"); 353 } 354 355 /** 356 * @covers \progress_trace_buffer 357 */ 358 public function test_progress_trace_buffer() { 359 $this->resetAfterTest(false); 360 361 $trace = new progress_trace_buffer(new html_progress_trace()); 362 ob_start(); 363 $trace->output('do'); 364 $trace->output('re', 1); 365 $trace->output('mi', 2); 366 $trace->finished(); 367 $output = ob_get_contents(); 368 ob_end_clean(); 369 $this->assertSame("<p>do</p>\n<p>  re</p>\n<p>    mi</p>\n", $output); 370 $this->assertSame($output, $trace->get_buffer()); 371 372 $trace = new progress_trace_buffer(new html_progress_trace(), false); 373 $trace->output('do'); 374 $trace->output('re', 1); 375 $trace->output('mi', 2); 376 $trace->finished(); 377 $this->assertSame("<p>do</p>\n<p>  re</p>\n<p>    mi</p>\n", $trace->get_buffer()); 378 $this->assertSame("<p>do</p>\n<p>  re</p>\n<p>    mi</p>\n", $trace->get_buffer()); 379 $trace->reset_buffer(); 380 $this->assertSame('', $trace->get_buffer()); 381 $this->expectOutputString(''); 382 } 383 384 /** 385 * @covers \combined_progress_trace 386 */ 387 public function test_combined_progress_trace() { 388 $this->resetAfterTest(false); 389 390 $trace1 = new progress_trace_buffer(new html_progress_trace(), false); 391 $trace2 = new progress_trace_buffer(new text_progress_trace(), false); 392 393 $trace = new combined_progress_trace(array($trace1, $trace2)); 394 $trace->output('do'); 395 $trace->output('re', 1); 396 $trace->output('mi', 2); 397 $trace->finished(); 398 $this->assertSame("<p>do</p>\n<p>  re</p>\n<p>    mi</p>\n", $trace1->get_buffer()); 399 $this->assertSame("do\n re\n mi\n", $trace2->get_buffer()); 400 $this->expectOutputString(''); 401 } 402 403 /** 404 * @covers ::set_debugging 405 */ 406 public function test_set_debugging() { 407 global $CFG; 408 409 $this->resetAfterTest(); 410 411 $this->assertEquals(DEBUG_DEVELOPER, $CFG->debug); 412 $this->assertTrue($CFG->debugdeveloper); 413 $this->assertNotEmpty($CFG->debugdisplay); 414 415 set_debugging(DEBUG_DEVELOPER, true); 416 $this->assertEquals(DEBUG_DEVELOPER, $CFG->debug); 417 $this->assertTrue($CFG->debugdeveloper); 418 $this->assertNotEmpty($CFG->debugdisplay); 419 420 set_debugging(DEBUG_DEVELOPER, false); 421 $this->assertEquals(DEBUG_DEVELOPER, $CFG->debug); 422 $this->assertTrue($CFG->debugdeveloper); 423 $this->assertEmpty($CFG->debugdisplay); 424 425 set_debugging(-1); 426 $this->assertEquals(-1, $CFG->debug); 427 $this->assertTrue($CFG->debugdeveloper); 428 429 set_debugging(DEBUG_ALL); 430 $this->assertEquals(DEBUG_ALL, $CFG->debug); 431 $this->assertFalse($CFG->debugdeveloper); 432 433 set_debugging(DEBUG_NORMAL); 434 $this->assertEquals(DEBUG_NORMAL, $CFG->debug); 435 $this->assertFalse($CFG->debugdeveloper); 436 437 set_debugging(DEBUG_MINIMAL); 438 $this->assertEquals(DEBUG_MINIMAL, $CFG->debug); 439 $this->assertFalse($CFG->debugdeveloper); 440 441 set_debugging(DEBUG_NONE); 442 $this->assertEquals(DEBUG_NONE, $CFG->debug); 443 $this->assertFalse($CFG->debugdeveloper); 444 } 445 446 /** 447 * @covers ::strip_pluginfile_content 448 */ 449 public function test_strip_pluginfile_content() { 450 $source = <<<SOURCE 451 Hello! 452 453 I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness. 454 455 URL outside a tag: https://moodle.org/logo/logo-240x60.gif 456 Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif 457 458 External link 1:<img src='https://moodle.org/logo/logo-240x60.gif' alt='Moodle'/> 459 External link 2:<img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif"/> 460 Internal link 1:<img src='@@PLUGINFILE@@/logo-240x60.gif' alt='Moodle'/> 461 Internal link 2:<img alt="Moodle" src="@@PLUGINFILE@@logo-240x60.gif"/> 462 Anchor link 1:<a href="@@PLUGINFILE@@logo-240x60.gif" alt="bananas">Link text</a> 463 Anchor link 2:<a title="bananas" href="../logo-240x60.gif">Link text</a> 464 Anchor + ext. img:<a title="bananas" href="../logo-240x60.gif"><img alt="Moodle" src="@@PLUGINFILE@@logo-240x60.gif"/></a> 465 Ext. anchor + img:<a href="@@PLUGINFILE@@logo-240x60.gif"><img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif"/></a> 466 SOURCE; 467 $expected = <<<EXPECTED 468 Hello! 469 470 I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness. 471 472 URL outside a tag: https://moodle.org/logo/logo-240x60.gif 473 Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif 474 475 External link 1:<img src="https://moodle.org/logo/logo-240x60.gif" alt="Moodle" /> 476 External link 2:<img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif" /> 477 Internal link 1: 478 Internal link 2: 479 Anchor link 1:Link text 480 Anchor link 2:<a title="bananas" href="../logo-240x60.gif">Link text</a> 481 Anchor + ext. img:<a title="bananas" href="../logo-240x60.gif"></a> 482 Ext. anchor + img:<img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif" /> 483 EXPECTED; 484 $this->assertSame($expected, strip_pluginfile_content($source)); 485 } 486 487 /** 488 * @covers \purify_html 489 */ 490 public function test_purify_html_ruby() { 491 492 $this->resetAfterTest(); 493 494 $ruby = 495 "<p><ruby><rb>京都</rb><rp>(</rp><rt>きょうと</rt><rp>)</rp></ruby>は" . 496 "<ruby><rb>日本</rb><rp>(</rp><rt>にほん</rt><rp>)</rp></ruby>の" . 497 "<ruby><rb>都</rb><rp>(</rp><rt>みやこ</rt><rp>)</rp></ruby>です。</p>"; 498 $illegal = '<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>'; 499 500 $cleaned = purify_html($ruby . $illegal); 501 $this->assertEquals($ruby, $cleaned); 502 503 } 504 505 /** 506 * Tests for content_to_text. 507 * 508 * @param string $content The content 509 * @param int|false $format The content format 510 * @param string $expected Expected value 511 * @dataProvider provider_content_to_text 512 * @covers ::content_to_text 513 */ 514 public function test_content_to_text($content, $format, $expected) { 515 $content = content_to_text($content, $format); 516 $this->assertEquals($expected, $content); 517 } 518 519 /** 520 * Data provider for test_content_to_text. 521 */ 522 public static function provider_content_to_text() { 523 return array( 524 array('asd', false, 'asd'), 525 // Trim '\r\n '. 526 array("Note that:\n\n3 > 1 ", FORMAT_PLAIN, "Note that:\n\n3 > 1"), 527 array("Note that:\n\n3 > 1\r\n", FORMAT_PLAIN, "Note that:\n\n3 > 1"), 528 // Multiple spaces to one. 529 array('<span class="eheh">京都</span> -> hehe', FORMAT_HTML, '京都 -> hehe'), 530 array('<span class="eheh">京都</span> -> hehe', false, '京都 -> hehe'), 531 array('asd asd', false, 'asd asd'), 532 // From markdown to html and html to text. 533 array('asd __lera__ con la', FORMAT_MARKDOWN, 'asd LERA con la'), 534 // HTML to text. 535 array('<p class="frogs">This is a <strong class=\'fishes\'>test</strong></p>', FORMAT_HTML, 'This is a TEST'), 536 array("<span lang='en' class='multilang'>english</span> 537 <span lang='ca' class='multilang'>català</span> 538 <span lang='es' class='multilang'>español</span> 539 <span lang='fr' class='multilang'>français</span>", FORMAT_HTML, "english català español français") 540 ); 541 } 542 543 /** 544 * Data provider for validate_email() function. 545 * 546 * @return array Returns aray of test data for the test_validate_email function 547 */ 548 public function data_validate_email() { 549 return [ 550 // Test addresses that should pass. 551 [ 552 'email' => 'moodle@example.com', 553 'result' => true 554 ], 555 [ 556 'email' => 'moodle@localhost.local', 557 'result' => true 558 ], 559 [ 560 'email' => 'verp_email+is=mighty@moodle.org', 561 'result' => true 562 ], 563 [ 564 'email' => "but_potentially'dangerous'too@example.org", 565 'result' => true 566 ], 567 [ 568 'email' => 'posts+AAAAAAAAAAIAAAAAAAAGQQAAAAABFSXz1eM/P/lR2bYyljM+@posts.moodle.org', 569 'result' => true 570 ], 571 572 // Test addresses that should NOT pass. 573 [ 574 'email' => 'moodle@localhost', 575 'result' => false 576 ], 577 [ 578 'email' => '"attacker\\" -oQ/tmp/ -X/var/www/vhost/moodle/backdoor.php some"@email.com', 579 'result' => false 580 ], 581 [ 582 'email' => "moodle@example.com>\r\nRCPT TO:<victim@example.com", 583 'result' => false 584 ], 585 [ 586 'email' => 'greater>than@example.com', 587 'result' => false 588 ], 589 [ 590 'email' => 'less<than@example.com', 591 'result' => false 592 ], 593 [ 594 'email' => '"this<is>validbutwerejectit"@example.com', 595 'result' => false 596 ], 597 598 // Empty e-mail addresess are not valid. 599 [ 600 'email' => '', 601 'result' => false, 602 ], 603 [ 604 'email' => null, 605 'result' => false, 606 ], 607 [ 608 'email' => false, 609 'result' => false, 610 ], 611 612 // Extra email addresses from Wikipedia page on Email Addresses. 613 // Valid. 614 [ 615 'email' => 'simple@example.com', 616 'result' => true 617 ], 618 [ 619 'email' => 'very.common@example.com', 620 'result' => true 621 ], 622 [ 623 'email' => 'disposable.style.email.with+symbol@example.com', 624 'result' => true 625 ], 626 [ 627 'email' => 'other.email-with-hyphen@example.com', 628 'result' => true 629 ], 630 [ 631 'email' => 'fully-qualified-domain@example.com', 632 'result' => true 633 ], 634 [ 635 'email' => 'user.name+tag+sorting@example.com', 636 'result' => true 637 ], 638 // One-letter local-part. 639 [ 640 'email' => 'x@example.com', 641 'result' => true 642 ], 643 [ 644 'email' => 'example-indeed@strange-example.com', 645 'result' => true 646 ], 647 // See the List of Internet top-level domains. 648 [ 649 'email' => 'example@s.example', 650 'result' => true 651 ], 652 // Quoted double dot. 653 [ 654 'email' => '"john..doe"@example.org', 655 'result' => true 656 ], 657 658 // Invalid. 659 // No @ character. 660 [ 661 'email' => 'Abc.example.com', 662 'result' => false 663 ], 664 // Only one @ is allowed outside quotation marks. 665 [ 666 'email' => 'A@b@c@example.com', 667 'result' => false 668 ], 669 // None of the special characters in this local-part are allowed outside quotation marks. 670 [ 671 'email' => 'a"b(c)d,e:f;g<h>i[j\k]l@example.com', 672 'result' => false 673 ], 674 // Quoted strings must be dot separated or the only element making up the local-part. 675 [ 676 'email' => 'just"not"right@example.com', 677 'result' => false 678 ], 679 // Spaces, quotes, and backslashes may only exist when within quoted strings and preceded by a backslash. 680 [ 681 'email' => 'this is"not\allowed@example.com', 682 'result' => false 683 ], 684 // Even if escaped (preceded by a backslash), spaces, quotes, and backslashes must still be contained by quotes. 685 [ 686 'email' => 'this\ still\"not\\allowed@example.com', 687 'result' => false 688 ], 689 // Local part is longer than 64 characters. 690 [ 691 'email' => '1234567890123456789012345678901234567890123456789012345678901234+x@example.com', 692 'result' => false 693 ], 694 ]; 695 } 696 697 /** 698 * Tests valid and invalid email address using the validate_email() function. 699 * 700 * @param string $email the email address to test 701 * @param boolean $result Expected result (true or false) 702 * @dataProvider data_validate_email 703 * @covers ::validate_email 704 */ 705 public function test_validate_email($email, $result) { 706 if ($result) { 707 $this->assertTrue(validate_email($email)); 708 } else { 709 $this->assertFalse(validate_email($email)); 710 } 711 } 712 713 /** 714 * Data provider for test_get_file_argument. 715 */ 716 public static function provider_get_file_argument() { 717 return array( 718 // Serving SCORM content w/o HTTP GET params. 719 array(array( 720 'SERVER_SOFTWARE' => 'Apache', 721 'SERVER_PORT' => '80', 722 'REQUEST_METHOD' => 'GET', 723 'REQUEST_URI' => '/pluginfile.php/3854/mod_scorm/content/1/swf.html', 724 'SCRIPT_NAME' => '/pluginfile.php', 725 'PATH_INFO' => '/3854/mod_scorm/content/1/swf.html', 726 ), 0, '/3854/mod_scorm/content/1/swf.html'), 727 array(array( 728 'SERVER_SOFTWARE' => 'Apache', 729 'SERVER_PORT' => '80', 730 'REQUEST_METHOD' => 'GET', 731 'REQUEST_URI' => '/pluginfile.php/3854/mod_scorm/content/1/swf.html', 732 'SCRIPT_NAME' => '/pluginfile.php', 733 'PATH_INFO' => '/3854/mod_scorm/content/1/swf.html', 734 ), 1, '/3854/mod_scorm/content/1/swf.html'), 735 // Serving SCORM content w/ HTTP GET 'file' as first param. 736 array(array( 737 'SERVER_SOFTWARE' => 'Apache', 738 'SERVER_PORT' => '80', 739 'REQUEST_METHOD' => 'GET', 740 'REQUEST_URI' => '/pluginfile.php/3854/mod_scorm/content/1/swf.html?file=video_.swf', 741 'SCRIPT_NAME' => '/pluginfile.php', 742 'PATH_INFO' => '/3854/mod_scorm/content/1/swf.html', 743 ), 0, '/3854/mod_scorm/content/1/swf.html'), 744 array(array( 745 'SERVER_SOFTWARE' => 'Apache', 746 'SERVER_PORT' => '80', 747 'REQUEST_METHOD' => 'GET', 748 'REQUEST_URI' => '/pluginfile.php/3854/mod_scorm/content/1/swf.html?file=video_.swf', 749 'SCRIPT_NAME' => '/pluginfile.php', 750 'PATH_INFO' => '/3854/mod_scorm/content/1/swf.html', 751 ), 1, '/3854/mod_scorm/content/1/swf.html'), 752 // Serving SCORM content w/ HTTP GET 'file' not as first param. 753 array(array( 754 'SERVER_SOFTWARE' => 'Apache', 755 'SERVER_PORT' => '80', 756 'REQUEST_METHOD' => 'GET', 757 'REQUEST_URI' => '/pluginfile.php/3854/mod_scorm/content/1/swf.html?foo=bar&file=video_.swf', 758 'SCRIPT_NAME' => '/pluginfile.php', 759 'PATH_INFO' => '/3854/mod_scorm/content/1/swf.html', 760 ), 0, '/3854/mod_scorm/content/1/swf.html'), 761 array(array( 762 'SERVER_SOFTWARE' => 'Apache', 763 'SERVER_PORT' => '80', 764 'REQUEST_METHOD' => 'GET', 765 'REQUEST_URI' => '/pluginfile.php/3854/mod_scorm/content/1/swf.html?foo=bar&file=video_.swf', 766 'SCRIPT_NAME' => '/pluginfile.php', 767 'PATH_INFO' => '/3854/mod_scorm/content/1/swf.html', 768 ), 1, '/3854/mod_scorm/content/1/swf.html'), 769 // Serving content from a generic activity w/ HTTP GET 'file', still forcing slash arguments. 770 array(array( 771 'SERVER_SOFTWARE' => 'Apache', 772 'SERVER_PORT' => '80', 773 'REQUEST_METHOD' => 'GET', 774 'REQUEST_URI' => '/pluginfile.php/3854/whatever/content/1/swf.html?file=video_.swf', 775 'SCRIPT_NAME' => '/pluginfile.php', 776 'PATH_INFO' => '/3854/whatever/content/1/swf.html', 777 ), 0, '/3854/whatever/content/1/swf.html'), 778 array(array( 779 'SERVER_SOFTWARE' => 'Apache', 780 'SERVER_PORT' => '80', 781 'REQUEST_METHOD' => 'GET', 782 'REQUEST_URI' => '/pluginfile.php/3854/whatever/content/1/swf.html?file=video_.swf', 783 'SCRIPT_NAME' => '/pluginfile.php', 784 'PATH_INFO' => '/3854/whatever/content/1/swf.html', 785 ), 1, '/3854/whatever/content/1/swf.html'), 786 // Serving content from a generic activity w/ HTTP GET 'file', still forcing slash arguments (edge case). 787 array(array( 788 'SERVER_SOFTWARE' => 'Apache', 789 'SERVER_PORT' => '80', 790 'REQUEST_METHOD' => 'GET', 791 'REQUEST_URI' => '/pluginfile.php/?file=video_.swf', 792 'SCRIPT_NAME' => '/pluginfile.php', 793 'PATH_INFO' => '/', 794 ), 0, 'video_.swf'), 795 array(array( 796 'SERVER_SOFTWARE' => 'Apache', 797 'SERVER_PORT' => '80', 798 'REQUEST_METHOD' => 'GET', 799 'REQUEST_URI' => '/pluginfile.php/?file=video_.swf', 800 'SCRIPT_NAME' => '/pluginfile.php', 801 'PATH_INFO' => '/', 802 ), 1, 'video_.swf'), 803 // Serving content from a generic activity w/ HTTP GET 'file', w/o forcing slash arguments. 804 array(array( 805 'SERVER_SOFTWARE' => 'Apache', 806 'SERVER_PORT' => '80', 807 'REQUEST_METHOD' => 'GET', 808 'REQUEST_URI' => '/pluginfile.php?file=%2F3854%2Fwhatever%2Fcontent%2F1%2Fswf.html%3Ffile%3Dvideo_.swf', 809 'SCRIPT_NAME' => '/pluginfile.php', 810 ), 0, '/3854/whatever/content/1/swf.html?file=video_.swf'), 811 array(array( 812 'SERVER_SOFTWARE' => 'Apache', 813 'SERVER_PORT' => '80', 814 'REQUEST_METHOD' => 'GET', 815 'REQUEST_URI' => '/pluginfile.php?file=%2F3854%2Fwhatever%2Fcontent%2F1%2Fswf.html%3Ffile%3Dvideo_.swf', 816 'SCRIPT_NAME' => '/pluginfile.php', 817 ), 1, '/3854/whatever/content/1/swf.html?file=video_.swf'), 818 ); 819 } 820 821 /** 822 * Tests for get_file_argument() function. 823 * 824 * @param array $server mockup for $_SERVER. 825 * @param string $cfgslasharguments slasharguments setting. 826 * @param string|false $expected Expected value. 827 * @dataProvider provider_get_file_argument 828 * @covers ::get_file_argument 829 */ 830 public function test_get_file_argument($server, $cfgslasharguments, $expected) { 831 global $CFG; 832 833 // Overwrite the related settings. 834 $currentsetting = $CFG->slasharguments; 835 $CFG->slasharguments = $cfgslasharguments; 836 // Mock global $_SERVER. 837 $currentserver = isset($_SERVER) ? $_SERVER : null; 838 $_SERVER = $server; 839 initialise_fullme(); 840 if ($_SERVER['REQUEST_METHOD'] !== 'GET') { 841 $this->fail('Only HTTP GET mocked request allowed.'); 842 } 843 if (empty($_SERVER['REQUEST_URI'])) { 844 $this->fail('Invalid HTTP GET mocked request.'); 845 } 846 // Mock global $_GET. 847 $currentget = isset($_GET) ? $_GET : null; 848 $_GET = array(); 849 $querystring = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); 850 if (!empty($querystring)) { 851 $_SERVER['QUERY_STRING'] = $querystring; 852 parse_str($querystring, $_GET); 853 } 854 855 $this->assertEquals($expected, get_file_argument()); 856 857 // Restore the current settings and global values. 858 $CFG->slasharguments = $currentsetting; 859 if (is_null($currentserver)) { 860 unset($_SERVER); 861 } else { 862 $_SERVER = $currentserver; 863 } 864 if (is_null($currentget)) { 865 unset($_GET); 866 } else { 867 $_GET = $currentget; 868 } 869 } 870 871 /** 872 * Tests for extract_draft_file_urls_from_text() function. 873 * 874 * @covers ::extract_draft_file_urls_from_text 875 */ 876 public function test_extract_draft_file_urls_from_text() { 877 global $CFG; 878 879 $url1 = "{$CFG->wwwroot}/draftfile.php/5/user/draft/99999999/test1.jpg"; 880 $url2 = "{$CFG->wwwroot}/draftfile.php/5/user/draft/99999998/test2.jpg"; 881 882 $html = "<p>This is a test.</p><p><img src=\"$url1}\" alt=\"\" role=\"presentation\"></p> 883 <br>Test content.<p></p><p><img src=\"{$url2}\" alt=\"\" width=\"2048\" height=\"1536\" 884 role=\"presentation\" class=\"img-fluid atto_image_button_text-bottom\"><br></p>"; 885 $draftareas = array( 886 array( 887 'urlbase' => 'draftfile.php', 888 'contextid' => '5', 889 'component' => 'user', 890 'filearea' => 'draft', 891 'itemid' => '99999999', 892 'filename' => 'test1.jpg', 893 0 => "{$CFG->wwwroot}/draftfile.php/5/user/draft/99999999/test1.jpg", 894 1 => 'draftfile.php', 895 2 => '5', 896 3 => 'user', 897 4 => 'draft', 898 5 => '99999999', 899 6 => 'test1.jpg' 900 ), 901 array( 902 'urlbase' => 'draftfile.php', 903 'contextid' => '5', 904 'component' => 'user', 905 'filearea' => 'draft', 906 'itemid' => '99999998', 907 'filename' => 'test2.jpg', 908 0 => "{$CFG->wwwroot}/draftfile.php/5/user/draft/99999998/test2.jpg", 909 1 => 'draftfile.php', 910 2 => '5', 911 3 => 'user', 912 4 => 'draft', 913 5 => '99999998', 914 6 => 'test2.jpg' 915 ) 916 ); 917 $extracteddraftareas = extract_draft_file_urls_from_text($html, false, 5, 'user', 'draft'); 918 $this->assertEquals($draftareas, $extracteddraftareas); 919 } 920 921 /** 922 * @covers ::print_password_policy 923 */ 924 public function test_print_password_policy() { 925 $this->resetAfterTest(true); 926 global $CFG; 927 928 $policydisabled = ''; 929 930 // Set password policy to disabled. 931 $CFG->passwordpolicy = false; 932 933 // Check for empty response. 934 $this->assertEquals($policydisabled, print_password_policy()); 935 936 // Now set the policy to enabled with every control disabled. 937 $CFG->passwordpolicy = true; 938 $CFG->minpasswordlength = 0; 939 $CFG->minpassworddigits = 0; 940 $CFG->minpasswordlower = 0; 941 $CFG->minpasswordupper = 0; 942 $CFG->minpasswordnonalphanum = 0; 943 $CFG->maxconsecutiveidentchars = 0; 944 945 // Check for empty response. 946 $this->assertEquals($policydisabled, print_password_policy()); 947 948 // Now enable some controls, and check that the policy responds with policy text. 949 $CFG->minpasswordlength = 8; 950 $CFG->minpassworddigits = 1; 951 $CFG->minpasswordlower = 1; 952 $CFG->minpasswordupper = 1; 953 $CFG->minpasswordnonalphanum = 1; 954 $CFG->maxconsecutiveidentchars = 1; 955 956 $this->assertNotEquals($policydisabled, print_password_policy()); 957 } 958 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body