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
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
;
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();
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
);
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
);
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
);
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
);
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
//
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
);
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
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
//
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
);
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
//
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
//
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
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
);
190 public void acceptingLeftInsertOnRightSideAndRejectingRightInsertOnRightSideAfterwards()
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
//
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
//
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
209 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin
, left
, right
);
210 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin
, right
, left
);
214 public void acceptingLeftInsertOnRightSideAndRejectingRightDeleteOnRightSideAfterwards()
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
//
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
//
227 final String right
= "They don't call it a Quarter Pounder with Cheese?" + NL
//
228 + "They call it a Royale with Cheese." + NL
//
232 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin
, left
, right
);
233 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin
, right
, left
);
237 public void acceptingLeftInsertOnRightSideAndRejectingRightChangeOnRightSideAfterwards()
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
//
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
//
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
);
260 public void acceptingLeftChangeOnRightSideAndRejectingRightInsertOnRightSideAfterwards()
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
//
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
//
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
);
283 public void acceptingLeftChangeOnRightSideAndRejectingRightDeleteOnRightSideAfterwards()
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
//
301 + "What do they call a Big Mac?";
303 assertAcceptingLeftOnRightSideAndRejectingRightOnRightSideIsLeftValue(origin
, left
, right
);
304 assertAcceptingRightOnLeftSideAndRejectingLeftOnLeftSideIsRightValue(origin
, right
, left
);
308 public void acceptingLeftChangeOnRightSideAndRejectingRightChangeOnRightSideAfterwards()
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
);
333 public void acceptingLeftDeleteOnRightSideAndRejectingRightInsertOnRightSideAfterwards()
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
//
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
);
359 public void acceptingLeftDeleteOnRightSideAndRejectingRightChangeOnRightSideAfterwards()
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
//
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
);
384 public void acceptingLeftDeleteOnRightSideAndRejectingRightDeleteOnRightSideAfterwards()
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
//
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
//
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
)
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
)
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
)
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
)
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
);
521 private String
nullIfEmpty(String string
) {
522 if (string
== null || string
.isEmpty()) {