[458147] Apply three-way merging also for rejecting attribute changes
[EMFCompare2.git] / plugins / org.eclipse.emf.compare.tests / src / org / eclipse / emf / compare / tests / merge / MultiLineAttributeMergeTest.java
bloba0a3f08b853cf7ba758cce270a52f1bb153f1aad
1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 EclipseSource Muenchen GmbH and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Philip Langer - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.emf.compare.tests.merge;
13 import static org.junit.Assert.assertEquals;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.List;
19 import org.eclipse.emf.common.util.BasicMonitor;
20 import org.eclipse.emf.compare.Comparison;
21 import org.eclipse.emf.compare.Diff;
22 import org.eclipse.emf.compare.DifferenceSource;
23 import org.eclipse.emf.compare.EMFCompare;
24 import org.eclipse.emf.compare.merge.BatchMerger;
25 import org.eclipse.emf.compare.merge.IBatchMerger;
26 import org.eclipse.emf.compare.merge.IMerger;
27 import org.eclipse.emf.compare.scope.DefaultComparisonScope;
28 import org.eclipse.emf.compare.scope.IComparisonScope;
29 import org.eclipse.emf.ecore.resource.Resource;
30 import org.junit.Test;
32 /**
33 * Tests merging of concurrent changes of multi-line string attributes.
35 * @author Philip Langer <planger@eclipsesource.com>
37 @SuppressWarnings("nls")
38 public class MultiLineAttributeMergeTest {
40 private static final String NL = "\n";
42 private IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
44 @Test
45 public void changeSingleLineTextOnOneSide() throws IOException {
46 final String origin = "They don't call it a Quarter Pounder with Cheese?";
47 final String left = "They don't call it a Quarter Pounder with Cheese?";
48 final String right = "They do not call it a Quarter Pounder with Cheese?"; // changed
49 final String merged = right;
51 assertRejectedAndMergedBidirectional(origin, left, right, merged);
54 @Test
55 public void addSingleLineTextOnOneSide() throws IOException {
56 final String origin = "";
57 final String left = "They don't call it a Quarter Pounder with Cheese?";
58 final String right = "";
59 final String merged = left;
61 assertRejectedAndMergedBidirectional(origin, left, right, merged);
64 @Test
65 public void unsetSingleLineTextOnOneSide() throws IOException {
66 final String origin = "They don't call it a Quarter Pounder with Cheese?";
67 final String left = "They don't call it a Quarter Pounder with Cheese?";
68 final String right = null; // unset
69 final String merged = right;
71 assertRejectedAndMergedBidirectional(origin, left, right, merged);
74 @Test
75 public void removeSingleLineTextOnOneSide() throws IOException {
76 final String origin = "They don't call it a Quarter Pounder with Cheese?";
77 final String left = "They don't call it a Quarter Pounder with Cheese?";
78 final String right = ""; // removed
79 final String merged = null; // empty String is interpreted as unset by EMF Compare
81 assertRejectedAndMergedBidirectional(origin, left, right, merged);
84 @Test
85 public void changeAndRemoveLinesInMultiLineTextOnOneSide() throws IOException {
86 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
87 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
88 + "What do they call it?" + NL //
89 + "They call it a Royale with Cheese." + NL //
90 + "Royale with Cheese." + NL //
91 + "That's right." + NL //
92 + "What do they call a Big Mac?" + NL //
93 + "A Big Mac's a Big Mac, but they call it Le Big Mac.";
95 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
96 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
97 + "What do they call it?" + NL //
98 + "They call it a Royale with Cheese." + NL //
99 + "Royale with Cheese." + NL //
100 + "That's right." + NL //
101 + "What do they call a Big Mac?" + NL //
102 + "A Big Mac's a Big Mac, but they call it Le Big Mac.";
104 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
105 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
106 + "What _do_ they call it?" + NL // changed
107 + "They call it a Royale with Cheese." + NL //
108 + "" // removed
109 + "That's right." + NL //
110 + "What do they call a Big Mac?" + NL //
111 + "A Big Mac's a Big Mac, but they call it Le Big Mac.";
113 final String merged = right;
115 assertRejectedAndMergedBidirectional(origin, left, right, merged);
118 @Test
119 public void changeAndRemoveDifferentLinesInMultiLineOnTextBothSides() throws IOException {
120 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
121 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
122 + "What do they call it?" + NL //
123 + "They call it a Royale with Cheese." + NL //
124 + "Royale with Cheese." + NL //
125 + "That's right." + NL //
126 + "What do they call a Big Mac?" + NL //
127 + "A Big Mac's a Big Mac, but they call it Le Big Mac.";
129 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
130 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
131 + "What do they call it?" + NL //
132 + "They call it a Royale with Cheese." + NL //
133 + "Royale with Cheese." + NL //
134 + "That's right." + NL //
135 + "What do they call a \"Big Mac\"?" // changed
136 + ""; // removed
138 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
139 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
140 + "What _do_ they call it?" + NL // changed
141 + "They call it a Royale with Cheese." + NL //
142 + "" // removed
143 + "That's right." + NL //
144 + "What do they call a Big Mac?" + NL //
145 + "A Big Mac's a Big Mac, but they call it Le Big Mac.";
147 final String merged = "They don't call it a Quarter Pounder with Cheese?" + NL //
148 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL //
149 + "What _do_ they call it?" + NL // changed right
150 + "They call it a Royale with Cheese." + NL //
151 + "" // removed right
152 + "That's right." + NL //
153 + "What do they call a \"Big Mac\"?" // changed left
154 + ""; // removed left
156 assertRejectedAndMergedBidirectional(origin, left, right, merged);
159 @Test
160 public void addDifferentLineAtDifferentLineInMultiLineText() throws IOException {
161 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
162 + "They call it a Royale with Cheese." + NL //
163 + "Royale with Cheese." + NL //
164 + "That's right.";
166 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
167 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL // added
168 + "They call it a Royale with Cheese." + NL //
169 + "Royale with Cheese." + NL //
170 + "That's right.";
172 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
173 + "They call it a Royale with Cheese." + NL //
174 + "Royale with Cheese." + NL //
175 + "That's right." + NL //
176 + "What do they call a Big Mac?"; // added
178 final String merged = "They don't call it a Quarter Pounder with Cheese?" + NL //
179 + "Nah, they got the metric system, they wouldn't know what a Quarter Pounder is." + NL // added
180 // left
181 + "They call it a Royale with Cheese." + NL //
182 + "Royale with Cheese." + NL //
183 + "That's right." + NL //
184 + "What do they call a Big Mac?"; // added right;
186 assertRejectedAndMergedBidirectional(origin, left, right, merged);
189 @Test
190 public void acceptingLeftInsertOnRightSideAndRejectingRightInsertOnRightSideAfterwards()
191 throws IOException {
192 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
193 + "They call it a Royale with Cheese." + NL //
194 + "Royale with Cheese." + NL //
195 + "That's right.";
197 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
198 + "Nah, they got the metric system." + NL // added
199 + "They call it a Royale with Cheese." + NL //
200 + "Royale with Cheese." + NL //
201 + "That's right.";
203 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
204 + "They call it a Royale with Cheese." + NL //
205 + "Royale with Cheese." + NL //
206 + "What do they call a Big Mac?" + NL // added
207 + "That's right.";
209 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
210 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
213 @Test
214 public void acceptingLeftInsertOnRightSideAndRejectingRightDeleteOnRightSideAfterwards()
215 throws IOException {
216 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
217 + "They call it a Royale with Cheese." + NL //
218 + "Royale with Cheese." + NL //
219 + "That's right.";
221 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
222 + "Nah, they got the metric system." + NL // added
223 + "They call it a Royale with Cheese." + NL //
224 + "Royale with Cheese." + NL //
225 + "That's right.";
227 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
228 + "They call it a Royale with Cheese." + NL //
229 + "" // deleted
230 + "That's right.";
232 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
233 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
236 @Test
237 public void acceptingLeftInsertOnRightSideAndRejectingRightChangeOnRightSideAfterwards()
238 throws IOException {
239 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
240 + "They call it a Royale with Cheese." + NL //
241 + "Royale with Cheese." + NL //
242 + "That's right.";
244 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
245 + "Nah, they got the metric system." + NL // added
246 + "They call it a Royale with Cheese." + NL //
247 + "Royale with Cheese." + NL //
248 + "That's right.";
250 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
251 + "They call it a Royale with Cheese." + NL //
252 + "Royale with Cheese." + NL //
253 + "That's right!!!!"; // changed
255 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
256 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
259 @Test
260 public void acceptingLeftChangeOnRightSideAndRejectingRightInsertOnRightSideAfterwards()
261 throws IOException {
262 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
263 + "They call it a Royale with Cheese." + NL //
264 + "Royale with Cheese." + NL //
265 + "That's right.";
267 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
268 + "They call it a Royale with Cheese!!!" + NL // changed
269 + "Royale with Cheese." + NL //
270 + "That's right.";
272 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
273 + "They call it a Royale with Cheese." + NL //
274 + "Royale with Cheese." + NL //
275 + "What do they call a Big Mac?" + NL// added
276 + "That's right."; //
278 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
279 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
282 @Test
283 public void acceptingLeftChangeOnRightSideAndRejectingRightDeleteOnRightSideAfterwards()
284 throws IOException {
285 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
286 + "They call it a Royale with Cheese." + NL //
287 + "Royale with Cheese." + NL //
288 + "That's right." + NL //
289 + "What do they call a Big Mac?";
291 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
292 + "They call it a Royale with Cheese!!!" + NL // changed
293 + "Royale with Cheese." + NL //
294 + "That's right." + NL //
295 + "What do they call a Big Mac?";
297 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
298 + "They call it a Royale with Cheese." + NL //
299 + "Royale with Cheese." + NL //
300 + "" // deleted
301 + "What do they call a Big Mac?";
303 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
304 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
307 @Test
308 public void acceptingLeftChangeOnRightSideAndRejectingRightChangeOnRightSideAfterwards()
309 throws IOException {
310 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
311 + "They call it a Royale with Cheese." + NL //
312 + "Royale with Cheese." + NL //
313 + "That's right." + NL //
314 + "What do they call a Big Mac?";
316 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
317 + "They call it a Royale with Cheese!!!" + NL // changed
318 + "Royale with Cheese." + NL //
319 + "That's right." + NL //
320 + "What do they call a Big Mac?";
322 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
323 + "They call it a Royale with Cheese." + NL //
324 + "Royale with Cheese." + NL //
325 + "That's right." + NL //
326 + "What do they call a Big Mac?????"; // changed
328 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
329 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
332 @Test
333 public void acceptingLeftDeleteOnRightSideAndRejectingRightInsertOnRightSideAfterwards()
334 throws IOException {
335 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
336 + "They call it a Royale with Cheese." + NL //
337 + "Royale with Cheese." + NL //
338 + "That's right." + NL //
339 + "What do they call a Big Mac?";
341 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
342 + "" // deleted
343 + "Royale with Cheese." + NL //
344 + "That's right." + NL //
345 + "What do they call a Big Mac?";
347 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
348 + "They call it a Royale with Cheese." + NL //
349 + "Royale with Cheese." + NL //
350 + "That's right." + NL //
351 + "That's freaking right." + NL // added
352 + "What do they call a Big Mac?";
354 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
355 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
358 @Test
359 public void acceptingLeftDeleteOnRightSideAndRejectingRightChangeOnRightSideAfterwards()
360 throws IOException {
361 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
362 + "They call it a Royale with Cheese." + NL //
363 + "Royale with Cheese." + NL //
364 + "That's right." + NL //
365 + "What do they call a Big Mac?";
367 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
368 + "" // deleted
369 + "Royale with Cheese." + NL //
370 + "That's right." + NL //
371 + "What do they call a Big Mac?";
373 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
374 + "They call it a Royale with Cheese." + NL //
375 + "Royale with Cheese." + NL //
376 + "That's right." + NL //
377 + "What do they call a Big Mac?????"; // changed
379 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
380 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
383 @Test
384 public void acceptingLeftDeleteOnRightSideAndRejectingRightDeleteOnRightSideAfterwards()
385 throws IOException {
386 final String origin = "They don't call it a Quarter Pounder with Cheese?" + NL //
387 + "They call it a Royale with Cheese." + NL //
388 + "Royale with Cheese." + NL //
389 + "That's right." + NL //
390 + "What do they call a Big Mac?";
392 final String left = "They don't call it a Quarter Pounder with Cheese?" + NL //
393 + "" // deleted
394 + "Royale with Cheese." + NL //
395 + "That's right." + NL //
396 + "What do they call a Big Mac?";
398 final String right = "They don't call it a Quarter Pounder with Cheese?" + NL //
399 + "They call it a Royale with Cheese." + NL //
400 + "Royale with Cheese." + NL //
401 + "" // deleted
402 + "What do they call a Big Mac?"; // changed
404 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin, left, right);
405 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin, right, left);
408 private void assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(final String origin,
409 final String left, final String right) throws IOException {
410 final ThreeWayAttributeMergeScenario scenario = createMergeScenario(origin, left, right);
411 final Comparison comparison = compare(scenario);
412 acceptLeft(comparison);
413 rejectRight(comparison);
415 final String rightValue = scenario.getRightAttributeValue();
416 assertEquals(nullIfEmpty(left), nullIfEmpty(rightValue));
419 private void assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(final String origin,
420 final String left, final String right) throws IOException {
421 final ThreeWayAttributeMergeScenario scenario = createMergeScenario(origin, left, right);
422 final Comparison comparison = compare(scenario);
423 acceptRight(comparison);
424 rejectLeft(comparison);
426 final String leftValue = scenario.getLeftAttributeValue();
427 assertEquals(nullIfEmpty(right), nullIfEmpty(leftValue));
430 private void assertRejectedAndMergedBidirectional(String origin, String left, String right, String merged)
431 throws IOException {
432 assertRejectLeft(origin, left, right);
433 assertRejectRight(origin, left, right);
434 assertMergedLeftToRight(origin, left, right, merged);
435 assertMergedRightToLeft(origin, left, right, merged);
438 private void assertRejectLeft(String origin, String left, String right) throws IOException {
439 final ThreeWayAttributeMergeScenario scenario = createMergeScenario(origin, left, right);
440 final Comparison comparison = compare(scenario);
441 rejectLeft(comparison);
442 final String attributeValue = scenario.getLeftAttributeValue();
443 assertEquals(nullIfEmpty(origin), nullIfEmpty(attributeValue));
446 private void assertRejectRight(String origin, String left, String right) throws IOException {
447 final ThreeWayAttributeMergeScenario scenario = createMergeScenario(origin, left, right);
448 final Comparison comparison = compare(scenario);
449 rejectRight(comparison);
450 final String attributeValue = scenario.getRightAttributeValue();
451 assertEquals(nullIfEmpty(origin), nullIfEmpty(attributeValue));
454 private void assertMergedLeftToRight(String origin, String left, String right, String merged)
455 throws IOException {
456 final ThreeWayAttributeMergeScenario scenario = createMergeScenario(origin, left, right);
457 final Comparison comparison = compare(scenario);
458 acceptLeft(comparison);
459 final String attributeValue = scenario.getRightAttributeValue();
460 assertEquals(nullIfEmpty(merged), nullIfEmpty(attributeValue));
463 private void assertMergedRightToLeft(String origin, String left, String right, String merged)
464 throws IOException {
465 final ThreeWayAttributeMergeScenario scenario = createMergeScenario(origin, left, right);
466 final Comparison comparison = compare(scenario);
467 acceptRight(comparison);
468 final String attributeValue = scenario.getLeftAttributeValue();
469 assertEquals(nullIfEmpty(merged), nullIfEmpty(attributeValue));
472 private void rejectLeft(Comparison comparison) {
473 final List<Diff> leftDiffs = getDiffsForSource(comparison.getDifferences(), DifferenceSource.LEFT);
474 final IBatchMerger merger = new BatchMerger(mergerRegistry);
475 merger.copyAllRightToLeft(leftDiffs, new BasicMonitor());
478 private void rejectRight(Comparison comparison) {
479 final List<Diff> rightDiffs = getDiffsForSource(comparison.getDifferences(), DifferenceSource.RIGHT);
480 final IBatchMerger merger = new BatchMerger(mergerRegistry);
481 merger.copyAllLeftToRight(rightDiffs, new BasicMonitor());
484 private void acceptRight(Comparison comparison) {
485 final List<Diff> rightDiffs = getDiffsForSource(comparison.getDifferences(), DifferenceSource.RIGHT);
486 final IBatchMerger merger = new BatchMerger(mergerRegistry);
487 merger.copyAllRightToLeft(rightDiffs, new BasicMonitor());
490 private void acceptLeft(Comparison comparison) {
491 final List<Diff> leftDiffs = getDiffsForSource(comparison.getDifferences(), DifferenceSource.LEFT);
492 final IBatchMerger merger = new BatchMerger(mergerRegistry);
493 merger.copyAllLeftToRight(leftDiffs, new BasicMonitor());
496 private List<Diff> getDiffsForSource(List<Diff> differences, DifferenceSource source) {
497 List<Diff> diffsForSource = new ArrayList<Diff>();
498 for (Diff diff : differences) {
499 if (source.equals(diff.getSource())) {
500 diffsForSource.add(diff);
503 return diffsForSource;
506 private ThreeWayAttributeMergeScenario createMergeScenario(String origin, String left, String right)
507 throws IOException {
508 return new ThreeWayAttributeMergeScenario(origin, left, right);
511 private Comparison compare(final ThreeWayAttributeMergeScenario scenario) {
512 final Resource origin = scenario.getOriginResource();
513 final Resource left = scenario.getLeftResource();
514 final Resource right = scenario.getRightResource();
516 final IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
517 final Comparison comparison = EMFCompare.builder().build().compare(scope);
518 return comparison;
521 private String nullIfEmpty(String string) {
522 if (string == null || string.isEmpty()) {
523 return null;
524 } else {
525 return string;