@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 287 lines 6.6 kB view raw
1<?php 2 3final class PhutilProseDiffTestCase 4 extends PhabricatorTestCase { 5 6 public function testTrimApart() { 7 $map = array( 8 '' => array(), 9 'a' => array('a'), 10 ' a ' => array( 11 ' ', 12 'a', 13 ' ', 14 ), 15 ' a' => array( 16 ' ', 17 'a', 18 ), 19 'a ' => array( 20 'a', 21 ' ', 22 ), 23 ' a b ' => array( 24 ' ', 25 'a b', 26 ' ', 27 ), 28 ); 29 30 foreach ($map as $input => $expect) { 31 $actual = PhutilProseDifferenceEngine::trimApart($input); 32 $this->assertEqual( 33 $expect, 34 $actual, 35 pht('Trim Apart: %s', $input)); 36 } 37 } 38 39 public function testProseDiffsDistance() { 40 $this->assertProseParts( 41 '', 42 '', 43 array(), 44 pht('Empty')); 45 46 $this->assertProseParts( 47 "xxx\nyyy", 48 "xxx\nzzz\nyyy", 49 array( 50 "= xxx\n", 51 "+ zzz\n", 52 '= yyy', 53 ), 54 pht('Add Paragraph')); 55 56 $this->assertProseParts( 57 "xxx\nzzz\nyyy", 58 "xxx\nyyy", 59 array( 60 "= xxx\n", 61 "- zzz\n", 62 '= yyy', 63 ), 64 pht('Remove Paragraph')); 65 66 $this->assertProseParts( 67 'xxx', 68 "xxxyyy\n.zzz", 69 array( 70 '= xxx', 71 "+ yyy\n.zzz", 72 ), 73 pht('Amend paragraph, and add paragraph starting with punctuation')); 74 75 // Without smoothing, the alogorithm identifies that "shark" and "cat" 76 // both contain the letter "a" and tries to express this as a very 77 // fine-grained edit which replaces "sh" with "c" and then "rk" with "t". 78 // This is technically correct, but it is much easier for human viewers to 79 // parse if we smooth this into a single removal and a single addition. 80 81 $this->assertProseParts( 82 'They say the shark has nine lives.', 83 'They say the cat has nine lives.', 84 array( 85 '= They say the ', 86 '- shark', 87 '+ cat', 88 '= has nine lives.', 89 ), 90 pht('"Shark/cat" word edit smoothenss.')); 91 92 $this->assertProseParts( 93 'Rising quickly, she says', 94 'Rising quickly, she remarks:', 95 array( 96 '= Rising quickly, she ', 97 '- says', 98 '+ remarks:', 99 ), 100 pht('"Says/remarks" word edit smoothenss.')); 101 102 $this->assertProseParts( 103 'See screenshots', 104 'Viewed video files', 105 array( 106 '- See screenshots', 107 '+ Viewed video files', 108 ), 109 pht('Complete paragraph rewrite.')); 110 111 $this->assertProseParts( 112 'xaaax', 113 'xbbbx', 114 array( 115 '- xaaax', 116 '+ xbbbx', 117 ), 118 pht('Whole word rewrite with common prefix and suffix.')); 119 120 $this->assertProseParts( 121 ' aaa ', 122 ' bbb ', 123 array( 124 '= ', 125 '- aaa', 126 '+ bbb', 127 '= ', 128 ), 129 pht('Whole word rewrite with whitespace prefix and suffix.')); 130 131 $this->assertSummaryProseParts( 132 "a\nb\nc\nd\ne\nf\ng\nh\n", 133 "a\nb\nc\nd\nX\nf\ng\nh\n", 134 array( 135 '.', 136 "= d\n", 137 '- e', 138 '+ X', 139 "= \nf", 140 '.', 141 ), 142 pht('Summary diff with middle change.')); 143 144 $this->assertSummaryProseParts( 145 "a\nb\nc\nd\ne\nf\ng\nh\n", 146 "X\nb\nc\nd\ne\nf\ng\nh\n", 147 array( 148 '- a', 149 '+ X', 150 "= \nb", 151 '.', 152 ), 153 pht('Summary diff with head change.')); 154 155 $this->assertSummaryProseParts( 156 "a\nb\nc\nd\ne\nf\ng\nh\n", 157 "a\nb\nc\nd\ne\nf\ng\nX\n", 158 array( 159 '.', 160 "= g\n", 161 '- h', 162 '+ X', 163 "= \n", 164 ), 165 pht('Summary diff with last change.')); 166 167 $this->assertProseParts( 168 'aaa aaa aaa aaa, bbb bbb bbb bbb.', 169 "aaa aaa aaa aaa, bbb bbb bbb bbb.\n\n- ccc ccc ccc", 170 array( 171 '= aaa aaa aaa aaa, bbb bbb bbb bbb.', 172 "+ \n\n- ccc ccc ccc", 173 ), 174 pht('Diff with new trailing content.')); 175 176 $this->assertProseParts( 177 'aaa aaa aaa aaa, bbb bbb bbb bbb.', 178 'aaa aaa aaa aaa bbb bbb bbb bbb.', 179 array( 180 '= aaa aaa aaa aaa', 181 '- ,', 182 '= bbb bbb bbb bbb.', 183 ), 184 pht('Diff with a removed comma.')); 185 186 $this->assertProseParts( 187 'aaa aaa aaa aaa, bbb bbb bbb bbb.', 188 "aaa aaa aaa aaa bbb bbb bbb bbb.\n\n- ccc ccc ccc!", 189 array( 190 '= aaa aaa aaa aaa', 191 '- ,', 192 '= bbb bbb bbb bbb.', 193 "+ \n\n- ccc ccc ccc!", 194 ), 195 pht('Diff with a removed comma and new trailing content.')); 196 197 $this->assertProseParts( 198 '[ ] Walnuts', 199 '[X] Walnuts', 200 array( 201 '= [', 202 '- ', 203 '+ X', 204 '= ] Walnuts', 205 ), 206 pht('Diff adding a tickmark to a checkbox list.')); 207 208 $this->assertProseParts( 209 '[[ ./week49 ]]', 210 '[[ ./week50 ]]', 211 array( 212 '= [[ ./week', 213 '- 49', 214 '+ 50', 215 '= ]]', 216 ), 217 pht('Diff changing a remarkup wiki link target.')); 218 219 // Create a large corpus with many sentences and paragraphs. 220 $large_paragraph = 'xyz. '; 221 $large_paragraph = str_repeat($large_paragraph, 50); 222 $large_paragraph = rtrim($large_paragraph); 223 224 $large_corpus = $large_paragraph."\n\n"; 225 $large_corpus = str_repeat($large_corpus, 50); 226 $large_corpus = rtrim($large_corpus); 227 228 $this->assertProseParts( 229 $large_corpus, 230 "aaa\n\n".$large_corpus."\n\nzzz", 231 array( 232 "+ aaa\n\n", 233 '= '.$large_corpus, 234 "+ \n\nzzz", 235 ), 236 pht('Adding initial and final lines to a large corpus.')); 237 238 } 239 240 private function assertProseParts($old, $new, array $expect_parts, $label) { 241 $engine = new PhutilProseDifferenceEngine(); 242 $diff = $engine->getDiff($old, $new); 243 244 $parts = $diff->getParts(); 245 246 $this->assertParts($expect_parts, $parts, $label); 247 } 248 249 private function assertSummaryProseParts( 250 $old, 251 $new, 252 array $expect_parts, 253 $label) { 254 255 $engine = new PhutilProseDifferenceEngine(); 256 $diff = $engine->getDiff($old, $new); 257 258 $parts = $diff->getSummaryParts(); 259 260 $this->assertParts($expect_parts, $parts, $label); 261 } 262 263 private function assertParts( 264 array $expect, 265 array $actual_parts, 266 $label) { 267 268 $actual = array(); 269 foreach ($actual_parts as $actual_part) { 270 $type = $actual_part['type']; 271 $text = $actual_part['text']; 272 273 switch ($type) { 274 case '.': 275 $actual[] = $type; 276 break; 277 default: 278 $actual[] = "{$type} {$text}"; 279 break; 280 } 281 } 282 283 $this->assertEqual($expect, $actual, $label); 284 } 285 286 287}