From c110115cc09448b20eb1a1528e63fcb56ec8ceff 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 69621008bfd..00ff10e1827 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -3793,38 +3793,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 82a050d67bc260066848009463076a9c0f704a5a 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 59fcd1c132f..5a6ef0577e3 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8375,11 +8375,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 00ff10e1827..8c02d58b1b8 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -3822,6 +3822,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 6a62cbe59998c2939fa0ef8c390fb11a2830542c 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 5a6ef0577e3..2a7b5a10ff3 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8352,10 +8352,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 8c02d58b1b8..d3733c768a2 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -3792,7 +3792,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. @@ -3809,16 +3809,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-"], ]; }