Some text more text'; $to = 'Other text more text'; $diff = HtmlDiff::compareHtml($from, $to); $this->assertEquals('Some Other text more text', $diff, false); // Note that the end result here isn't perfect (there are new spaces where there weren't before)... // If we make improvements later on that keep only the original spaces, that would be preferred. // This test is more here to protect against any unexpected changes to the spacing, so that we can make an intentional // decision as to whether those changes are desirable. $diff = HtmlDiff::compareHtml($from, $to, true); $this->assertEquals('<span> Some Other text </span> <span> more text </span>', $diff, true); } /** * The underlying SebastianBergmann\Diff\Differ class has a special constant for end of line differences * but we shouldn't ever encounter that because of the way we're modifying the values before passing them * in to that class. */ public function testEndOfLineDoesntNeedHandling() { $from = 'some change' . "\r"; $to = 'some change' . "\n"; // If we encounter an end-of-line difference, these should throw exceptions $this->assertSame('some change', HtmlDiff::compareHtml($from, $to, true)); $this->assertSame('some change', HtmlDiff::compareHtml($from, $to)); $this->assertSame('some change', HtmlDiff::compareHtml($to, $from, true)); $this->assertSame('some change', HtmlDiff::compareHtml($to, $from)); // Ensure that this test is valid and that those changes would include an end-of-line warning // in a direct call to the underlying differ $differ = new Differ(); $expected = [ [ '#Warning: Strings contain different line endings!' . "\n", Differ::DIFF_LINE_END_WARNING, ], [ $from, Differ::REMOVED, ], [ $to, Differ::ADDED, ], ]; $this->assertSame($expected, $differ->diffToArray($from, $to)); } public function provideCompareHtml(): array { return [ [ 'from' => '

Some text

', 'to' => '

Other text

', 'escape' => false, 'expected' => '

SomeOther text

', ], [ 'from' => '

Some text

', 'to' => 'Other text', 'escape' => false, 'expected' => '

Some text

Other text', ], [ 'from' => '

Some text

', 'to' => '

Other text

', 'escape' => false, 'expected' => '

Some textOther text

', ], [ 'from' => '

About

', 'to' => '

About

', 'escape' => false, 'expected' => '

About

About

', ], [ 'from' => '

About

A comprehensive Library

', 'to' => '

About

A comprehensive

', 'escape' => false, 'expected' => '

About

A comprehensive Library

A comprehensive

', ], [ 'from' => '

Some textmore stuff

', 'to' => '

Some text

more stuff

', 'escape' => false, 'expected' => '

Sometextmorestuff

morestuff

', ], // Same examples as above, but with escaped HTML [ 'from' => '

Some text

', 'to' => '

Other text

', 'escape' => true, 'expected' => '<p><span>SomeOther text</span></p>', ], [ 'from' => '

Some text

', 'to' => 'Other text', 'escape' => true, 'expected' => '<p><span>SomeOther text</span></p>', ], [ 'from' => '

Some text

', 'to' => '

Other text

', 'escape' => true, 'expected' => '<p><span>SomeOther text</span></p>', ], [ 'from' => '

About

', 'to' => '

About

', 'escape' => true, // Note: This sees the whole h2 tag as being changed because of the initial call to explodeToHtmlChunks. // There is room to improve this in the future, but care would have to be taken not to aversely affect other scenarios. 'expected' => '<h2 class="mb-3 h4"><h2 class="mb-3 h2">About</h2>', ], [ 'from' => '

About

A comprehensive Library

', 'to' => '

About

A comprehensive

', 'escape' => true, 'expected' => '<div class="BorderGrid-cell"><h2 class="mb-3 h4">About</h2><span class="etc"><p class="f4 my-3">A comprehensive Library</p></span></div>', ], [ 'from' => '

Some textmore stuff

', 'to' => '

Some text

more stuff

', 'escape' => true, 'expected' => '<p><span>Some text</span><span></p><p>more stuff</span></p>', ], ]; } /** * @dataProvider provideCompareHtml */ public function testCompareHTML(string|array $from, string|array $to, bool $escape, string $expected) { $diff = HtmlDiff::compareHtml($from, $to, $escape); $this->assertEquals($this->removeWhiteSpace($expected), $this->removeWhiteSpace($diff)); } /** * @see https://groups.google.com/forum/#!topic/silverstripe-dev/yHcluCvuszo */ public function testTableDiff() { if (!class_exists('DOMDocument')) { $this->markTestSkipped('"DOMDocument" required'); return; } $from = '
Row 1
Row 2 Row 2
Row 3 Row 3
'; $to = '
Row 1
Row 2 Row 2
'; $expected = '' . $from . '' . '' . $to . ''; $compare = HtmlDiff::compareHtml($from, $to); $this->assertEquals($this->removeWhiteSpace($expected), $this->removeWhiteSpace($compare)); } /** * @see https://github.com/silverstripe/silverstripe-framework/issues/8053 */ public function testLegacyEachStatement() { $sentenceOne = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; $sentenceTwo = 'Nulla porttitor, ex quis commodo pharetra, diam dui efficitur justo, eu gravida elit eros vel libero.'; $from = "$sentenceOne $sentenceTwo"; $to = "$sentenceTwo $sentenceOne"; // We're cheating our test a little bit here, because depending on what HTML cleaner you have, you'll get // spaces added or not added around the tags. $quotedOne = preg_quote($sentenceOne, '/'); $quotedTwo = preg_quote($sentenceTwo, '/'); $expected = '/^ *' . $quotedOne . '<\/del> *' . $quotedTwo . ' *' . $quotedOne . '<\/ins> *$/'; $actual = HtmlDiff::compareHtml($from, $to); $this->assertMatchesRegularExpression($expected, $actual); } public function testDiffArray() { $from = ['Lorem', ['array here please ignore'], 'ipsum dolor']; $to = 'Lorem,ipsum'; $expected = '/^Lorem,ipsum *dolor<\/del> *$/'; $actual = HtmlDiff::compareHtml($from, $to); $this->assertMatchesRegularExpression($expected, $actual); } private function removeWhiteSpace(string $value): string { return preg_replace('/[\s]*/', '', $value); } }