Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

MergeAlgorithmTest.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com>
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.merge;
  44. import static org.junit.Assert.assertEquals;
  45. import java.io.ByteArrayOutputStream;
  46. import java.io.IOException;
  47. import org.eclipse.jgit.diff.RawText;
  48. import org.eclipse.jgit.diff.RawTextComparator;
  49. import org.eclipse.jgit.lib.Constants;
  50. import org.junit.Assume;
  51. import org.junit.Test;
  52. import org.junit.experimental.theories.DataPoints;
  53. import org.junit.experimental.theories.Theories;
  54. import org.junit.runner.RunWith;
  55. @RunWith(Theories.class)
  56. public class MergeAlgorithmTest {
  57. MergeFormatter fmt=new MergeFormatter();
  58. private final boolean newlineAtEnd;
  59. @DataPoints
  60. public static boolean[] newlineAtEndDataPoints = { false, true };
  61. public MergeAlgorithmTest(boolean newlineAtEnd) {
  62. this.newlineAtEnd = newlineAtEnd;
  63. }
  64. /**
  65. * Check for a conflict where the second text was changed similar to the
  66. * first one, but the second texts modification covers one more line.
  67. *
  68. * @throws IOException
  69. */
  70. @Test
  71. public void testTwoConflictingModifications() throws IOException {
  72. assertEquals(t("a<b=Z>Zdefghij"),
  73. merge("abcdefghij", "abZdefghij", "aZZdefghij"));
  74. }
  75. /**
  76. * Test a case where we have three consecutive chunks. The first text
  77. * modifies all three chunks. The second text modifies the first and the
  78. * last chunk. This should be reported as one conflicting region.
  79. *
  80. * @throws IOException
  81. */
  82. @Test
  83. public void testOneAgainstTwoConflictingModifications() throws IOException {
  84. assertEquals(t("aZ<Z=c>Zefghij"),
  85. merge("abcdefghij", "aZZZefghij", "aZcZefghij"));
  86. }
  87. /**
  88. * Test a merge where only the second text contains modifications. Expect as
  89. * merge result the second text.
  90. *
  91. * @throws IOException
  92. */
  93. @Test
  94. public void testNoAgainstOneModification() throws IOException {
  95. assertEquals(t("aZcZefghij"),
  96. merge("abcdefghij", "abcdefghij", "aZcZefghij"));
  97. }
  98. /**
  99. * Both texts contain modifications but not on the same chunks. Expect a
  100. * non-conflict merge result.
  101. *
  102. * @throws IOException
  103. */
  104. @Test
  105. public void testTwoNonConflictingModifications() throws IOException {
  106. assertEquals(t("YbZdefghij"),
  107. merge("abcdefghij", "abZdefghij", "Ybcdefghij"));
  108. }
  109. /**
  110. * Merge two complicated modifications. The merge algorithm has to extend
  111. * and combine conflicting regions to get to the expected merge result.
  112. *
  113. * @throws IOException
  114. */
  115. @Test
  116. public void testTwoComplicatedModifications() throws IOException {
  117. assertEquals(t("a<ZZZZfZhZj=bYdYYYYiY>"),
  118. merge("abcdefghij", "aZZZZfZhZj", "abYdYYYYiY"));
  119. }
  120. /**
  121. * Merge two modifications with a shared delete at the end. The underlying
  122. * diff algorithm has to provide consistent edit results to get the expected
  123. * merge result.
  124. *
  125. * @throws IOException
  126. */
  127. @Test
  128. public void testTwoModificationsWithSharedDelete() throws IOException {
  129. assertEquals(t("Cb}n}"),
  130. merge("ab}n}n}", "ab}n}", "Cb}n}"));
  131. }
  132. /**
  133. * Merge modifications with a shared insert in the middle. The
  134. * underlying diff algorithm has to provide consistent edit
  135. * results to get the expected merge result.
  136. *
  137. * @throws IOException
  138. */
  139. @Test
  140. public void testModificationsWithMiddleInsert() throws IOException {
  141. assertEquals(t("aBcd123123uvwxPq"),
  142. merge("abcd123uvwxpq", "aBcd123123uvwxPq", "abcd123123uvwxpq"));
  143. }
  144. /**
  145. * Merge modifications with a shared delete in the middle. The
  146. * underlying diff algorithm has to provide consistent edit
  147. * results to get the expected merge result.
  148. *
  149. * @throws IOException
  150. */
  151. @Test
  152. public void testModificationsWithMiddleDelete() throws IOException {
  153. assertEquals(t("Abz}z123Q"),
  154. merge("abz}z}z123q", "Abz}z123Q", "abz}z123q"));
  155. }
  156. /**
  157. * Test a conflicting region at the very start of the text.
  158. *
  159. * @throws IOException
  160. */
  161. @Test
  162. public void testConflictAtStart() throws IOException {
  163. assertEquals(t("<Z=Y>bcdefghij"),
  164. merge("abcdefghij", "Zbcdefghij", "Ybcdefghij"));
  165. }
  166. /**
  167. * Test a conflicting region at the very end of the text.
  168. *
  169. * @throws IOException
  170. */
  171. @Test
  172. public void testConflictAtEnd() throws IOException {
  173. assertEquals(t("abcdefghi<Z=Y>"),
  174. merge("abcdefghij", "abcdefghiZ", "abcdefghiY"));
  175. }
  176. /**
  177. * Check for a conflict where the second text was changed similar to the
  178. * first one, but the second texts modification covers one more line.
  179. *
  180. * @throws IOException
  181. */
  182. @Test
  183. public void testSameModification() throws IOException {
  184. assertEquals(t("abZdefghij"),
  185. merge("abcdefghij", "abZdefghij", "abZdefghij"));
  186. }
  187. /**
  188. * Check that a deleted vs. a modified line shows up as conflict (see Bug
  189. * 328551)
  190. *
  191. * @throws IOException
  192. */
  193. @Test
  194. public void testDeleteVsModify() throws IOException {
  195. assertEquals(t("ab<=Z>defghij"),
  196. merge("abcdefghij", "abdefghij", "abZdefghij"));
  197. }
  198. @Test
  199. public void testInsertVsModify() throws IOException {
  200. assertEquals(t("a<bZ=XY>"), merge("ab", "abZ", "aXY"));
  201. }
  202. @Test
  203. public void testAdjacentModifications() throws IOException {
  204. assertEquals(t("a<Zc=bY>d"), merge("abcd", "aZcd", "abYd"));
  205. }
  206. @Test
  207. public void testSeparateModifications() throws IOException {
  208. assertEquals(t("aZcYe"), merge("abcde", "aZcde", "abcYe"));
  209. }
  210. @Test
  211. public void testBlankLines() throws IOException {
  212. assertEquals(t("aZc\nYe"), merge("abc\nde", "aZc\nde", "abc\nYe"));
  213. }
  214. /**
  215. * Test merging two contents which do one similar modification and one
  216. * insertion is only done by one side, in the middle. Between modification
  217. * and insertion is a block which is common between the two contents and the
  218. * common base
  219. *
  220. * @throws IOException
  221. */
  222. @Test
  223. public void testTwoSimilarModsAndOneInsert() throws IOException {
  224. assertEquals(t("aBcDde"), merge("abcde", "aBcde", "aBcDde"));
  225. assertEquals(t("IAAAJCAB"), merge("iACAB", "IACAB", "IAAAJCAB"));
  226. assertEquals(t("HIAAAJCAB"), merge("HiACAB", "HIACAB", "HIAAAJCAB"));
  227. assertEquals(t("AGADEFHIAAAJCAB"),
  228. merge("AGADEFHiACAB", "AGADEFHIACAB", "AGADEFHIAAAJCAB"));
  229. }
  230. /**
  231. * Test merging two contents which do one similar modification and one
  232. * insertion is only done by one side, at the end. Between modification and
  233. * insertion is a block which is common between the two contents and the
  234. * common base
  235. *
  236. * @throws IOException
  237. */
  238. @Test
  239. public void testTwoSimilarModsAndOneInsertAtEnd() throws IOException {
  240. Assume.assumeTrue(newlineAtEnd);
  241. assertEquals(t("IAAJ"), merge("iA", "IA", "IAAJ"));
  242. assertEquals(t("IAJ"), merge("iA", "IA", "IAJ"));
  243. assertEquals(t("IAAAJ"), merge("iA", "IA", "IAAAJ"));
  244. }
  245. @Test
  246. public void testTwoSimilarModsAndOneInsertAtEndNoNewlineAtEnd()
  247. throws IOException {
  248. Assume.assumeFalse(newlineAtEnd);
  249. assertEquals(t("I<A=AAJ>"), merge("iA", "IA", "IAAJ"));
  250. assertEquals(t("I<A=AJ>"), merge("iA", "IA", "IAJ"));
  251. assertEquals(t("I<A=AAAJ>"), merge("iA", "IA", "IAAAJ"));
  252. }
  253. /**
  254. * Test situations where (at least) one input value is the empty text
  255. *
  256. * @throws IOException
  257. */
  258. @Test
  259. public void testEmptyTexts() throws IOException {
  260. // test modification against deletion
  261. assertEquals(t("<AB=>"), merge("A", "AB", ""));
  262. assertEquals(t("<=AB>"), merge("A", "", "AB"));
  263. // test unmodified against deletion
  264. assertEquals(t(""), merge("AB", "AB", ""));
  265. assertEquals(t(""), merge("AB", "", "AB"));
  266. // test deletion against deletion
  267. assertEquals(t(""), merge("AB", "", ""));
  268. }
  269. private String merge(String commonBase, String ours, String theirs) throws IOException {
  270. MergeResult r = new MergeAlgorithm().merge(RawTextComparator.DEFAULT,
  271. T(commonBase), T(ours), T(theirs));
  272. ByteArrayOutputStream bo=new ByteArrayOutputStream(50);
  273. fmt.formatMerge(bo, r, "B", "O", "T", Constants.CHARACTER_ENCODING);
  274. return new String(bo.toByteArray(), Constants.CHARACTER_ENCODING);
  275. }
  276. public String t(String text) {
  277. StringBuilder r = new StringBuilder();
  278. for (int i = 0; i < text.length(); i++) {
  279. char c = text.charAt(i);
  280. switch (c) {
  281. case '<':
  282. r.append("<<<<<<< O\n");
  283. break;
  284. case '=':
  285. r.append("=======\n");
  286. break;
  287. case '>':
  288. r.append(">>>>>>> T\n");
  289. break;
  290. default:
  291. r.append(c);
  292. if (newlineAtEnd || i < text.length() - 1)
  293. r.append('\n');
  294. }
  295. }
  296. return r.toString();
  297. }
  298. public RawText T(String text) {
  299. return new RawText(Constants.encode(t(text)));
  300. }
  301. }