previousLocaleSetting = null; // Set test handler ShortcodeParser::get('htmltest') ->register('test_shortcode', [TestShortcode::class, 'handle_shortcode']); ShortcodeParser::set_active('htmltest'); } protected function tearDown(): void { // If a test sets the locale, reset it on teardown if ($this->previousLocaleSetting) { setlocale(LC_CTYPE, $this->previousLocaleSetting); } ShortcodeParser::set_active('default'); parent::tearDown(); } /** * Test {@link Text->LimitCharacters()} */ public function providerLimitCharacters() { // HTML characters are stripped safely return [ ['The little brown fox jumped over the lazy cow.', 'The little brown fox…'], ['
Short & Sweet
', 'Short & Sweet'], ['This text contains & in it', 'This text contains &…'], ]; } /** * Test {@link DBHTMLText->LimitCharacters()} * * @dataProvider providerLimitCharacters * @param string $originalValue * @param string $expectedValue */ public function testLimitCharacters($originalValue, $expectedValue) { $textObj = DBField::create_field('HTMLFragment', $originalValue); $result = $textObj->obj('LimitCharacters')->forTemplate(); $this->assertEquals($expectedValue, $result); } /** * @return array */ public function providerLimitCharactersToClosestWord() { // HTML is converted safely to plain text return [ // Standard words limited, ellipsis added if truncated ['Lorem ipsum dolor sit amet
', 24, 'Lorem ipsum dolor sit…'], // Complete words less than the character limit don't get truncated, ellipsis not added ['Lorem ipsum
', 24, 'Lorem ipsum'], ['Lorem
', 24, 'Lorem'], ['', 24, ''], // No words produces nothing! // Special characters are encoded safely ['Nice & Easy', 24, 'Nice & Easy'], // HTML is safely converted to plain text ['Lorem ipsum dolor sit amet
', 24, 'Lorem ipsum dolor sit…'], ['Lorem ipsum dolor sit amet
', 24, 'Lorem ipsum dolor sit…'], ['Lorem ipsum
', 24, 'Lorem ipsum'], ['Lorem & ipsum dolor sit amet', 24, 'Lorem & ipsum dolor sit…'] ]; } /** * Test {@link DBHTMLText->LimitCharactersToClosestWord()} * * @dataProvider providerLimitCharactersToClosestWord * * @param string $originalValue Raw string input * @param int $limit * @param string $expectedValue Expected template value */ public function testLimitCharactersToClosestWord($originalValue, $limit, $expectedValue) { $textObj = DBField::create_field('HTMLFragment', $originalValue); $result = $textObj->obj('LimitCharactersToClosestWord', [$limit])->forTemplate(); $this->assertEquals($expectedValue, $result); } public function providerSummary() { return [ [ 'Should strip tags, but leave text
', 50, 'Should strip tags, but leave text', ], [ // Line breaks are preserved 'Unclosed tags
should not phase it
Second paragraph
should not cause errors or appear in output
', 50, "Second paragraphSecond paragraph
should not cause errors or appear in output
', 50, "Second paragraphSecond paragraph
should not cause errors or appear in output
', 50, "Second paragraphexample text words hello
', 50, 'example text words hello', ], // Shorter limits [ 'A long paragraph should be cut off if limit is set
', 5, 'A long paragraph should be…', ], [ 'No matter how many tags are in it
', 5, 'No matter how many tags…', ], [ 'A sentence is. nicer than hard limits
', 5, 'A sentence is.', ], ]; } /** * @dataProvider providerSummary * @param string $originalValue * @param int $limit * @param string $expectedValue */ public function testSummary($originalValue, $limit, $expectedValue) { $textObj = DBField::create_field('HTMLFragment', $originalValue); $result = $textObj->obj('Summary', [$limit])->forTemplate(); $this->assertEquals($expectedValue, $result); } public function testSummaryEndings() { $cases = [ '...', ' -> more', '' ]; $orig = 'Cut it off, cut it off
'; $match = 'Cut it off, cut'; foreach ($cases as $add) { $textObj = DBField::create_field('HTMLFragment', $orig); $result = $textObj->obj('Summary', [4, $add])->forTemplate(); $this->assertEquals($match . Convert::raw2xml($add), $result); } } public function providerFirstSentence() { return [ // Same behaviour as DBTextTest ['', ''], ['First sentence.', 'First sentence.'], ['First sentence. Second sentence', 'First sentence.'], ['First sentence? Second sentence', 'First sentence?'], ['First sentence! Second sentence', 'First sentence!'], // DBHTHLText strips HTML first ['First sentence. Second sentence. Third sentence
', 'First sentence.'], ]; } /** * @dataProvider providerFirstSentence * @param string $originalValue * @param string $expectedValue */ public function testFirstSentence($originalValue, $expectedValue) { $textObj = DBField::create_field('HTMLFragment', $originalValue); $result = $textObj->obj('FirstSentence')->forTemplate(); $this->assertEquals($expectedValue, $result); } public function testCreate() { /** @var DBHTMLText $field */ $field = Injector::inst()->create("HTMLFragment(['whitelist' => 'link'])", 'MyField'); $this->assertEquals(['link'], $field->getWhitelist()); $field = Injector::inst()->create("HTMLFragment(['whitelist' => 'link,a'])", 'MyField'); $this->assertEquals(['link', 'a'], $field->getWhitelist()); $field = Injector::inst()->create("HTMLFragment(['whitelist' => ['link', 'a']])", 'MyField'); $this->assertEquals(['link', 'a'], $field->getWhitelist()); $field = Injector::inst()->create("HTMLFragment", 'MyField'); $this->assertEmpty($field->getWhitelist()); // Test shortcodes $field = Injector::inst()->create("HTMLFragment(['shortcodes' => true])", 'MyField'); $this->assertEquals(true, $field->getProcessShortcodes()); $field = Injector::inst()->create("HTMLFragment(['shortcodes' => false])", 'MyField'); $this->assertEquals(false, $field->getProcessShortcodes()); // Mix options $field = Injector::inst()->create("HTMLFragment(['shortcodes' => true, 'whitelist' => ['a'])", 'MyField'); $this->assertEquals(true, $field->getProcessShortcodes()); $this->assertEquals(['a'], $field->getWhitelist()); } public function providerToPlain() { return [ [ 'Lots of HTML nested tags', 'Lots of HTML nested tags', ], [ '
Multi
Paragraph
Also has multilines.
Collapses
Excessive
Newlines
A dog ate a cat while looking at a Foobar
', 100, 'ate', // it should highlight 3 letters or more. 'A dog ate a cat while looking at a Foobar', ], [ 'This is a lot of text before this but really, this is a test sentence
with about more stuff after the line break
', 35, 'test', '… really, this is a test sentence…' ], [ 'This is a lot of text before this but really, this is a test sentence
with about more stuff after the line break
', 50, 'with', '… sentenceSome content [test_shortcode] with shortcode
' ); // Basic DBField methods process shortcodes $this->assertEquals( 'Some content shortcode content with shortcode', $obj->Plain() ); $this->assertEquals( 'Some content shortcode content with shortcode
', $obj->RAW() ); $this->assertEquals( '<p>Some content <strong>shortcode content</strong> with shortcode</p>', $obj->XML() ); $this->assertEquals( '<p>Some content <strong>shortcode content</strong> with shortcode</p>', $obj->HTML() ); // Test summary methods $this->assertEquals( 'Some content shortcode…', $obj->Summary(3) ); $this->assertEquals( 'Some content shortcode content with shortcode', $obj->LimitSentences(1) ); $this->assertEquals( 'Some content shortco…', $obj->LimitCharacters(20) ); } function testExists() { $h = new DBHTMLText(); $h->setValue(""); $this->assertFalse($h->exists()); $h->setValue("content
"); $this->assertTrue($h->exists()); } function testWhitelist() { $textObj = new DBHTMLText('Test', ['whitelist'=> 'meta,link']); $this->assertEquals( '', $textObj->whitelistContent('Remove
Remove Text'), 'Removes any elements not in whitelist excluding text elements' ); $textObj = new DBHTMLText('Test', ['whitelist'=> 'meta,link,text()']); $this->assertEquals( 'Keep Text', $textObj->whitelistContent('Remove
Keep Text'), 'Removes any elements not in whitelist including text elements' ); } public function testShortCodeParsedInRAW() { $parser = ShortcodeParser::get('HTMLTextTest'); $parser->register( 'shortcode', function ($arguments, $content, $parser, $tagName, $extra) { return 'replaced'; } ); ShortcodeParser::set_active('HTMLTextTest'); /** * @var DBHTMLText $field */ $field = DBField::create_field('HTMLText', '[shortcode]
'); $this->assertEquals('replaced
', $field->RAW()); $this->assertEquals('replaced
', (string)$field); $field->setOptions( [ 'shortcodes' => false, ] ); $this->assertEquals('[shortcode]
', $field->RAW()); $this->assertEquals('[shortcode]
', (string)$field); ShortcodeParser::set_active('default'); } public function testShortCodeParsedInTemplateHelpers() { $parser = ShortcodeParser::get('HTMLTextTest'); $parser->register( 'shortcode', function ($arguments, $content, $parser, $tagName, $extra) { return 'Replaced short code with this. home'; } ); ShortcodeParser::set_active('HTMLTextTest'); /** * @var DBHTMLText $field */ $field = DBField::create_field('HTMLText', '[shortcode]
'); $this->assertEquals( '<p>Replaced short code with this. <a href="home">home</a></p>', $field->HTMLATT() ); $this->assertEquals( '%3Cp%3EReplaced+short+code+with+this.+%3Ca+href%3D%22home%22%3Ehome%3C%2Fa%3E%3C%2Fp%3E', $field->URLATT() ); $this->assertEquals( '%3Cp%3EReplaced%20short%20code%20with%20this.%20%3Ca%20href%3D%22home%22%3Ehome%3C%2Fa%3E%3C%2Fp%3E', $field->RAWURLATT() ); $this->assertEquals( '<p>Replaced short code with this. <a href="home">home</a></p>', $field->ATT() ); $this->assertEquals( 'Replaced short code with this. home
', $field->RAW() ); $this->assertEquals( '\x3cp\x3eReplaced short code with this. \x3ca href=\"home\"\x3ehome\x3c/a\x3e\x3c/p\x3e', $field->JS() ); $this->assertEquals( '<p>Replaced short code with this. <a href="home">home</a></p>', $field->HTML() ); $this->assertEquals( '<p>Replaced short code with this. <a href="home">home</a></p>', $field->XML() ); $this->assertEquals( 'Repl...', $field->LimitCharacters(4, '...') ); $this->assertEquals( 'Replaced...', $field->LimitCharactersToClosestWord(10, '...') ); $this->assertEquals( 'Replaced...', $field->LimitWordCount(1, '...') ); $this->assertEquals( 'replaced short code with this. home
', $field->LowerCase() ); $this->assertEquals( 'REPLACED SHORT CODE WITH THIS. HOME
', $field->UpperCase() ); $this->assertEquals( 'Replaced short code with this. home', $field->Plain() ); Config::nest(); Director::config()->set('alternate_base_url', 'http://example.com/'); $this->assertEquals( 'Replaced short code with this. home
', $field->AbsoluteLinks() ); Config::unnest(); $this->assertEquals( 'Replaced short code with this.', $field->LimitSentences(1) ); $this->assertEquals( 'Replaced short code with this.', $field->FirstSentence() ); $this->assertEquals( 'Replaced short…', $field->Summary(2) ); $this->assertEquals( 'Replaced short code with this. home', $field->FirstParagraph() ); $this->assertEquals( 'Replaced short code with this. home', $field->ContextSummary(500, 'short code') ); ShortcodeParser::set_active('default'); } public function testValidUtf8() { // Install a UTF-8 locale $this->previousLocaleSetting = setlocale(LC_CTYPE, 0); $locales = ['en_US.UTF-8', 'en_NZ.UTF-8', 'de_DE.UTF-8']; $localeInstalled = false; foreach ($locales as $locale) { if ($localeInstalled = setlocale(LC_CTYPE, $locale)) { break; } } // If the system doesn't have any of the UTF-8 locales, exit early if ($localeInstalled === false) { $this->markTestIncomplete('Unable to run this test because of missing locale!'); return; } $problematicText = html_entity_decode('This is a Test with non-breaking space!
', ENT_COMPAT, 'UTF-8'); $textObj = new DBHTMLText('Test'); $textObj->setValue($problematicText); $this->assertTrue(mb_check_encoding($textObj->FirstSentence(), 'UTF-8')); $this->assertTrue(mb_check_encoding($textObj->Summary(), 'UTF-8')); } }