@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
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}