diff --git a/filter/activitynames/tests/filter_test.php b/filter/activitynames/tests/filter_test.php new file mode 100644 index 00000000000..403170efffe --- /dev/null +++ b/filter/activitynames/tests/filter_test.php @@ -0,0 +1,77 @@ +. + +/** + * Unit tests. + * + * @package filter_activitynames + * @category test + * @copyright 2018 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/filter/activitynames/filter.php'); // Include the code to test. + +/** + * Test case for the activity names auto-linking filter. + * + * @copyright 2018 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class filter_activitynames_filter_testcase extends advanced_testcase { + + public function test_links() { + global $CFG; + $this->resetAfterTest(true); + + // Create a test course. + $course = $this->getDataGenerator()->create_course(); + $context = context_course::instance($course->id); + + // Create two pages that will be linked to. + $page1 = $this->getDataGenerator()->create_module('page', + ['course' => $course->id, 'name' => 'Test 1']); + $page2 = $this->getDataGenerator()->create_module('page', + ['course' => $course->id, 'name' => 'Test (2)']); + + // Format text with all three entries in HTML. + $html = '
Please read the two pages Test 1 and Test (2).
'; + $filtered = format_text($html, FORMAT_HTML, array('context' => $context)); + + // Find all the glossary links in the result. + $matches = []; + preg_match_all('~([^<]*)~', + $filtered, $matches); + + // There should be 3 links links. + $this->assertEquals(2, count($matches[1])); + + // Check text of title attribute. + $this->assertEquals($page1->name, $matches[1][0]); + $this->assertEquals($page2->name, $matches[1][1]); + + // Check the ids in the links. + $this->assertEquals($page1->cmid, $matches[2][0]); + $this->assertEquals($page2->cmid, $matches[2][1]); + + // Check the link text. + $this->assertEquals($page1->name, $matches[3][0]); + $this->assertEquals($page2->name, $matches[3][1]); + } +} diff --git a/filter/glossary/tests/filter_test.php b/filter/glossary/tests/filter_test.php index f22822cf031..a5441bbf998 100644 --- a/filter/glossary/tests/filter_test.php +++ b/filter/glossary/tests/filter_test.php @@ -192,6 +192,52 @@ class filter_glossary_filter_testcase extends advanced_testcase { $this->assertEquals($glossary->name . ': normal', $matches[2][2]); } + /** + * Test brackets. + */ + public function test_brackets() { + global $CFG; + $this->resetAfterTest(true); + + // Enable glossary filter at top level. + filter_set_global_state('glossary', TEXTFILTER_ON); + $CFG->glossary_linkentries = 1; + + // Create a test course. + $course = $this->getDataGenerator()->create_course(); + $context = context_course::instance($course->id); + + // Create a glossary. + $glossary = $this->getDataGenerator()->create_module('glossary', + array('course' => $course->id, 'mainglossary' => 1)); + + // Create two entries with ampersands and one normal entry. + /** @var mod_glossary_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); + $simple = $generator->create_content($glossary, array('concept' => 'simple')); + $withbrackets = $generator->create_content($glossary, array('concept' => 'more complex (perhaps)')); + $test2 = $generator->create_content($glossary, array('concept' => 'Test (2)')); + + // Format text with all three entries in HTML. + $html = 'Some thigns are simple. Others are more complex (perhaps). Test (2).
'; + $filtered = format_text($html, FORMAT_HTML, array('context' => $context)); + + // Find all the glossary links in the result. + $matches = array(); + preg_match_all('~eid=([0-9]+).*?title="(.*?)"~', $filtered, $matches); + + // There should be 3 glossary links. + $this->assertEquals(3, count($matches[1])); + $this->assertEquals($simple->id, $matches[1][0]); + $this->assertEquals($withbrackets->id, $matches[1][1]); + $this->assertEquals($test2->id, $matches[1][2]); + + // Check text and escaping of title attribute. + $this->assertEquals($glossary->name . ': simple', $matches[2][0]); + $this->assertEquals($glossary->name . ': more complex (perhaps)', $matches[2][1]); + $this->assertEquals($glossary->name . ': Test (2)', $matches[2][2]); + } + public function test_exclude_excludes_link_to_entry_with_alias() { global $CFG, $GLOSSARY_EXCLUDEENTRY; diff --git a/lib/filterlib.php b/lib/filterlib.php index d991075af96..f210a257de5 100644 --- a/lib/filterlib.php +++ b/lib/filterlib.php @@ -1278,7 +1278,7 @@ function filter_phrases($text, $linkarray, $ignoretagsopen = null, $ignoretagscl // for things that have already been matched on this page. static $usedphrases = []; - $ignoretags = array(); // To store all the enclosig tags to be completely ignored. + $ignoretags = array(); // To store all the enclosing tags to be completely ignored. $tags = array(); // To store all the simple tags to be ignored. if (!$linkarrayalreadyprepared) { @@ -1418,8 +1418,15 @@ function filter_prepare_phrases_for_filtering(array $linkarray) { // Quote any regular expression characters and the delimiter in the work phrase to be searched. $linkobject->workregexp = preg_quote($linkobject->workregexp, '/'); + // If we ony want to match entire words then add \b assertions. However, only + // do this if the first or last thing in the phrase to match is a word character. if ($linkobject->fullmatch) { - $linkobject->workregexp = '\b' . $linkobject->workregexp . '\b'; + if (preg_match('~^\w~', $linkobject->workregexp)) { + $linkobject->workregexp = '\b' . $linkobject->workregexp; + } + if (preg_match('~\w$~', $linkobject->workregexp)) { + $linkobject->workregexp = $linkobject->workregexp . '\b'; + } } $linkobject->workregexp = '/(' . $linkobject->workregexp . ')/s';