Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/diff/prose/__tests__/PhutilProseDiffTestCase.php
- This file was added.
<?php | |||||
final class PhutilProseDiffTestCase extends PhutilTestCase { | |||||
public function testProseDiffsDistance() { | |||||
$this->assertProseParts( | |||||
'', | |||||
'', | |||||
array(), | |||||
pht('Empty')); | |||||
$this->assertProseParts( | |||||
"xxx\nyyy", | |||||
"xxx\nzzz\nyyy", | |||||
array( | |||||
"= xxx\n", | |||||
"+ zzz\n", | |||||
'= yyy', | |||||
), | |||||
pht('Add Paragraph')); | |||||
$this->assertProseParts( | |||||
"xxx\nzzz\nyyy", | |||||
"xxx\nyyy", | |||||
array( | |||||
"= xxx\n", | |||||
"- zzz\n", | |||||
'= yyy', | |||||
), | |||||
pht('Remove Paragraph')); | |||||
// Without smoothing, the alogorithm identifies that "shark" and "cat" | |||||
// both contain the letter "a" and tries to express this as a very | |||||
// fine-grained edit which replaces "sh" with "c" and then "rk" with "t". | |||||
// This is technically correct, but it is much easier for human viewers to | |||||
// parse if we smooth this into a single removal and a single addition. | |||||
$this->assertProseParts( | |||||
'They say the shark has nine lives.', | |||||
'They say the cat has nine lives.', | |||||
array( | |||||
'= They say the ', | |||||
'- shark', | |||||
'+ cat', | |||||
'= has nine lives.', | |||||
), | |||||
pht('"Shark/cat" word edit smoothenss.')); | |||||
$this->assertProseParts( | |||||
'Rising quickly, she says', | |||||
'Rising quickly, she remarks:', | |||||
array( | |||||
'= Rising quickly, she ', | |||||
'- says', | |||||
'+ remarks:', | |||||
), | |||||
pht('"Says/remarks" word edit smoothenss.')); | |||||
$this->assertProseParts( | |||||
'See screenshots', | |||||
'Viewed video files', | |||||
array( | |||||
'- See screenshots', | |||||
'+ Viewed video files', | |||||
), | |||||
pht('Complete paragraph rewrite.')); | |||||
$this->assertProseParts( | |||||
'xaaax', | |||||
'xbbbx', | |||||
array( | |||||
'- xaaax', | |||||
'+ xbbbx', | |||||
), | |||||
pht('Whole word rewrite with common prefix and suffix.')); | |||||
$this->assertProseParts( | |||||
' aaa ', | |||||
' bbb ', | |||||
array( | |||||
'= ', | |||||
'- aaa', | |||||
'+ bbb', | |||||
'= ', | |||||
), | |||||
pht('Whole word rewrite with whitespace prefix and suffix.')); | |||||
$this->assertSummaryProseParts( | |||||
"a\nb\nc\nd\ne\nf\ng\nh\n", | |||||
"a\nb\nc\nd\nX\nf\ng\nh\n", | |||||
array( | |||||
'.', | |||||
"= d\n", | |||||
'- e', | |||||
'+ X', | |||||
"= \nf", | |||||
'.', | |||||
), | |||||
pht('Summary diff with middle change.')); | |||||
$this->assertSummaryProseParts( | |||||
"a\nb\nc\nd\ne\nf\ng\nh\n", | |||||
"X\nb\nc\nd\ne\nf\ng\nh\n", | |||||
array( | |||||
'- a', | |||||
'+ X', | |||||
"= \nb", | |||||
'.', | |||||
), | |||||
pht('Summary diff with head change.')); | |||||
$this->assertSummaryProseParts( | |||||
"a\nb\nc\nd\ne\nf\ng\nh\n", | |||||
"a\nb\nc\nd\ne\nf\ng\nX\n", | |||||
array( | |||||
'.', | |||||
"= g\n", | |||||
'- h', | |||||
'+ X', | |||||
"= \n", | |||||
), | |||||
pht('Summary diff with last change.')); | |||||
$this->assertProseParts( | |||||
'aaa aaa aaa aaa, bbb bbb bbb bbb.', | |||||
"aaa aaa aaa aaa, bbb bbb bbb bbb.\n\n- ccc ccc ccc", | |||||
array( | |||||
'= aaa aaa aaa aaa, bbb bbb bbb bbb.', | |||||
"+ \n\n- ccc ccc ccc", | |||||
), | |||||
pht('Diff with new trailing content.')); | |||||
$this->assertProseParts( | |||||
'aaa aaa aaa aaa, bbb bbb bbb bbb.', | |||||
'aaa aaa aaa aaa bbb bbb bbb bbb.', | |||||
array( | |||||
'= aaa aaa aaa aaa', | |||||
'- ,', | |||||
'= bbb bbb bbb bbb.', | |||||
), | |||||
pht('Diff with a removed comma.')); | |||||
$this->assertProseParts( | |||||
'aaa aaa aaa aaa, bbb bbb bbb bbb.', | |||||
"aaa aaa aaa aaa bbb bbb bbb bbb.\n\n- ccc ccc ccc!", | |||||
array( | |||||
'= aaa aaa aaa aaa', | |||||
'- ,', | |||||
'= bbb bbb bbb bbb.', | |||||
"+ \n\n- ccc ccc ccc!", | |||||
), | |||||
pht('Diff with a removed comma and new trailing content.')); | |||||
$this->assertProseParts( | |||||
'[ ] Walnuts', | |||||
'[X] Walnuts', | |||||
array( | |||||
'= [', | |||||
'- ', | |||||
'+ X', | |||||
'= ] Walnuts', | |||||
), | |||||
pht('Diff adding a tickmark to a checkbox list.')); | |||||
$this->assertProseParts( | |||||
'[[ ./week49 ]]', | |||||
'[[ ./week50 ]]', | |||||
array( | |||||
'= [[ ./week', | |||||
'- 49', | |||||
'+ 50', | |||||
'= ]]', | |||||
), | |||||
pht('Diff changing a remarkup wiki link target.')); | |||||
// Create a large corpus with many sentences and paragraphs. | |||||
$large_paragraph = 'xyz. '; | |||||
$large_paragraph = str_repeat($large_paragraph, 50); | |||||
$large_paragraph = rtrim($large_paragraph); | |||||
$large_corpus = $large_paragraph."\n\n"; | |||||
$large_corpus = str_repeat($large_corpus, 50); | |||||
$large_corpus = rtrim($large_corpus); | |||||
$this->assertProseParts( | |||||
$large_corpus, | |||||
"aaa\n\n".$large_corpus."\n\nzzz", | |||||
array( | |||||
"+ aaa\n\n", | |||||
'= '.$large_corpus, | |||||
"+ \n\nzzz", | |||||
), | |||||
pht('Adding initial and final lines to a large corpus.')); | |||||
} | |||||
private function assertProseParts($old, $new, array $expect_parts, $label) { | |||||
$engine = new PhutilProseDifferenceEngine(); | |||||
$diff = $engine->getDiff($old, $new); | |||||
$parts = $diff->getParts(); | |||||
$this->assertParts($expect_parts, $parts, $label); | |||||
} | |||||
private function assertSummaryProseParts( | |||||
$old, | |||||
$new, | |||||
array $expect_parts, | |||||
$label) { | |||||
$engine = new PhutilProseDifferenceEngine(); | |||||
$diff = $engine->getDiff($old, $new); | |||||
$parts = $diff->getSummaryParts(); | |||||
$this->assertParts($expect_parts, $parts, $label); | |||||
} | |||||
private function assertParts( | |||||
array $expect, | |||||
array $actual_parts, | |||||
$label) { | |||||
$actual = array(); | |||||
foreach ($actual_parts as $actual_part) { | |||||
$type = $actual_part['type']; | |||||
$text = $actual_part['text']; | |||||
switch ($type) { | |||||
case '.': | |||||
$actual[] = $type; | |||||
break; | |||||
default: | |||||
$actual[] = "{$type} {$text}"; | |||||
break; | |||||
} | |||||
} | |||||
$this->assertEqual($expect, $actual, $label); | |||||
} | |||||
} |