From 82592f0c8432428307c2e28ba6fd12fbcaaf2e1f Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Tue, 19 Jan 2021 15:29:30 +0000 Subject: [PATCH 1/3] MDL-46256 word count: Convert existing tests to a data provider --- lib/tests/moodlelib_test.php | 57 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index 1648a8fb9fb..c9cd28c09d0 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -3746,38 +3746,35 @@ class core_moodlelib_testcase extends advanced_testcase { /** * Test function count_words(). + * + * @dataProvider count_words_testcases + * @param int $expectedcount number of words in $string. + * @param string $string the test string to count the words of. */ - public function test_count_words() { - $count = count_words("one two three'four"); - $this->assertEquals(3, $count); - - $count = count_words('one+two three’four'); - $this->assertEquals(3, $count); - - $count = count_words('one"two three-four'); - $this->assertEquals(2, $count); - - $count = count_words('one@two three_four'); - $this->assertEquals(4, $count); - - $count = count_words('one\two three/four'); - $this->assertEquals(4, $count); - - $count = count_words(' one ... two   three...four '); - $this->assertEquals(4, $count); - - $count = count_words('one.2 3,four'); - $this->assertEquals(4, $count); - - $count = count_words('1³ £2 €3.45 $6,789'); - $this->assertEquals(4, $count); - - $count = count_words('one—two ブルース カンベッル'); - $this->assertEquals(4, $count); - - $count = count_words('one…two ブルース … カンベッル'); - $this->assertEquals(4, $count); + public function test_count_words(int $expectedcount, string $string): void { + $this->assertEquals($expectedcount, count_words($string)); } + + /** + * Data provider for {@see test_count_words}. + * + * @return array of test cases. + */ + public function count_words_testcases(): array { + return [ + [3, "one two three'four"], + [3, 'one+two three’four'], + [2, 'one"two three-four'], + [4, 'one@two three_four'], + [4, 'one\two three/four'], + [4, ' one ... two   three...four '], + [4, 'one.2 3,four'], + [4, '1³ £2 €3.45 $6,789'], + [4, 'one—two ブルース カンベッル'], + [4, 'one…two ブルース … カンベッル'], + ]; + } + /** * Tests the getremoteaddr() function. */ From fbb0428179be164837a5bda31f4ccf83d1b286db Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Tue, 19 Jan 2021 15:50:05 +0000 Subject: [PATCH 2/3] MDL-46256 count_letters: an unit tests and fix HTML editity handling --- lib/moodlelib.php | 3 ++- lib/tests/moodlelib_test.php | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 363c95dea49..de054b5719e 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8357,11 +8357,12 @@ function count_words($string) { * Letters are defined as chars not in tags and different from whitespace. * * @category string - * @param string $string The text to be searched for letters. + * @param string $string The text to be searched for letters. May be HTML. * @return int The count of letters in the specified text. */ function count_letters($string) { $string = strip_tags($string); // Tags are out now. + $string = html_entity_decode($string); $string = preg_replace('/[[:space:]]*/', '', $string); // Whitespace are out now. return core_text::strlen($string); diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index c9cd28c09d0..856468fa834 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -3775,6 +3775,31 @@ class core_moodlelib_testcase extends advanced_testcase { ]; } + /** + * Test function {@see count_letters()}. + * + * @dataProvider count_letters_testcases + * @param int $expectedcount number of characters in $string. + * @param string $string the test string to count the letters of. + */ + public function test_count_letters(int $expectedcount, string $string): void { + $this->assertEquals($expectedcount, count_letters($string)); + } + + /** + * Data provider for {@see count_letters_testcases}. + * + * @return array of test cases. + */ + public function count_letters_testcases(): array { + return [ + [0, ''], + [1, 'x'], + [1, '&'], + [4, '

frog

'], + ]; + } + /** * Tests the getremoteaddr() function. */ From 96c8ad66f92ee4675144889fdc27bfc1f4bf189c Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Tue, 19 Jan 2021 15:39:24 +0000 Subject: [PATCH 3/3] MDL-46256 count_words: fix handling of paragraphs --- lib/moodlelib.php | 19 ++++++++++++++++++- lib/tests/moodlelib_test.php | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/moodlelib.php b/lib/moodlelib.php index de054b5719e..7b9d7eff60c 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8334,10 +8334,27 @@ function moodle_setlocale($locale='') { * Words are defined as things between whitespace. * * @category string - * @param string $string The text to be searched for words. + * @param string $string The text to be searched for words. May be HTML. * @return int The count of words in the specified string */ function count_words($string) { + // Before stripping tags, add a space after the close tag of anything that is not obviously inline. + // Also, br is a special case because it definitely delimits a word, but has no close tag. + $string = preg_replace('~ + ( # Capture the tag we match. + | b> | del> | em> | i> | + ins> | s> | small> | + strong> | sub> | sup> | u> + ) + \w+ # But, apart from those execptions, match any tag name. + > # End of close tag. + | +
| # Special cases that are not close tags. + ) + ~x', '$1 ', $string); // Add a space after the close tag. + // Now remove HTML tags. $string = strip_tags($string); // Decode HTML entities. $string = html_entity_decode($string); diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index 856468fa834..4f5d4ba1652 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -3745,7 +3745,7 @@ class core_moodlelib_testcase extends advanced_testcase { } /** - * Test function count_words(). + * Test function {@see count_words()}. * * @dataProvider count_words_testcases * @param int $expectedcount number of words in $string. @@ -3762,16 +3762,30 @@ class core_moodlelib_testcase extends advanced_testcase { */ public function count_words_testcases(): array { return [ + [0, ''], + [4, 'one two three four'], [3, "one two three'four"], [3, 'one+two three’four'], [2, 'one"two three-four'], [4, 'one@two three_four'], [4, 'one\two three/four'], + [4, '

one two

three four

'], + [4, '

one two
three four

'], + [4, '

one two
three four

'], // XHTML style. [4, ' one ... two   three...four '], [4, 'one.2 3,four'], [4, '1³ £2 €3.45 $6,789'], [4, 'one—two ブルース カンベッル'], [4, 'one…two ブルース … カンベッル'], + [4, '

one two

three four

'], + [4, '

one two


three four

'], + [4, '

one

  • two
  • three

four.

'], + [1, '

emphasis.

'], + [1, '

emphasis.

'], + [1, '

emphasis.

'], + [1, '

emphasis.

'], + [2, "one\ntwo"], + [1, "SO42-"], ]; }