test_rerere.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. """Tests for rerere functionality."""
  2. import tempfile
  3. import unittest
  4. from dulwich.rerere import (
  5. RerereCache,
  6. _extract_conflict_regions,
  7. _has_conflict_markers,
  8. _normalize_conflict_markers,
  9. _remove_conflict_markers,
  10. is_rerere_autoupdate,
  11. is_rerere_enabled,
  12. )
  13. class NormalizeConflictMarkersTests(unittest.TestCase):
  14. """Tests for _normalize_conflict_markers function."""
  15. def test_normalize_basic_conflict(self) -> None:
  16. """Test normalizing a basic conflict."""
  17. content = b"""line 1
  18. <<<<<<< ours
  19. our change
  20. =======
  21. their change
  22. >>>>>>> theirs
  23. line 2
  24. """
  25. expected = b"""line 1
  26. <<<<<<<
  27. our change
  28. =======
  29. their change
  30. >>>>>>>
  31. line 2
  32. """
  33. result = _normalize_conflict_markers(content)
  34. self.assertEqual(expected, result)
  35. def test_normalize_with_branch_names(self) -> None:
  36. """Test normalizing conflict with branch names."""
  37. content = b"""<<<<<<< HEAD
  38. content from HEAD
  39. =======
  40. content from feature
  41. >>>>>>> feature
  42. """
  43. expected = b"""<<<<<<<
  44. content from HEAD
  45. =======
  46. content from feature
  47. >>>>>>>
  48. """
  49. result = _normalize_conflict_markers(content)
  50. self.assertEqual(expected, result)
  51. class ExtractConflictRegionsTests(unittest.TestCase):
  52. """Tests for _extract_conflict_regions function."""
  53. def test_extract_single_conflict(self) -> None:
  54. """Test extracting a single conflict region."""
  55. content = b"""line 1
  56. <<<<<<< ours
  57. our change
  58. =======
  59. their change
  60. >>>>>>> theirs
  61. line 2
  62. """
  63. regions = _extract_conflict_regions(content)
  64. self.assertEqual(1, len(regions))
  65. ours, sep, theirs = regions[0]
  66. self.assertEqual(b"our change", ours)
  67. self.assertEqual(b"=======", sep)
  68. self.assertEqual(b"their change", theirs)
  69. def test_extract_multiple_conflicts(self) -> None:
  70. """Test extracting multiple conflict regions."""
  71. content = b"""<<<<<<< ours
  72. change 1
  73. =======
  74. change 2
  75. >>>>>>> theirs
  76. middle line
  77. <<<<<<< ours
  78. change 3
  79. =======
  80. change 4
  81. >>>>>>> theirs
  82. """
  83. regions = _extract_conflict_regions(content)
  84. self.assertEqual(2, len(regions))
  85. class HasConflictMarkersTests(unittest.TestCase):
  86. """Tests for _has_conflict_markers function."""
  87. def test_has_conflict_markers(self) -> None:
  88. """Test detecting conflict markers."""
  89. content = b"""<<<<<<< ours
  90. our change
  91. =======
  92. their change
  93. >>>>>>> theirs
  94. """
  95. self.assertTrue(_has_conflict_markers(content))
  96. def test_no_conflict_markers(self) -> None:
  97. """Test content without conflict markers."""
  98. content = b"""line 1
  99. line 2
  100. line 3
  101. """
  102. self.assertFalse(_has_conflict_markers(content))
  103. def test_partial_conflict_markers(self) -> None:
  104. """Test content with only some conflict markers."""
  105. content = b"""<<<<<<< ours
  106. our change
  107. line 3
  108. """
  109. self.assertFalse(_has_conflict_markers(content))
  110. class RemoveConflictMarkersTests(unittest.TestCase):
  111. """Tests for _remove_conflict_markers function."""
  112. def test_remove_conflict_markers(self) -> None:
  113. """Test removing conflict markers from resolved content."""
  114. content = b"""line 1
  115. <<<<<<< ours
  116. our change
  117. =======
  118. their change
  119. >>>>>>> theirs
  120. line 2
  121. """
  122. # This is a simplified test - in reality the resolved content
  123. # would have the user's chosen resolution
  124. result = _remove_conflict_markers(content)
  125. # The function keeps only lines outside conflict blocks
  126. self.assertNotIn(b"<<<<<<<", result)
  127. self.assertNotIn(b"=======", result)
  128. self.assertNotIn(b">>>>>>>", result)
  129. class RerereCacheTests(unittest.TestCase):
  130. """Tests for RerereCache class."""
  131. def setUp(self) -> None:
  132. """Set up test fixtures."""
  133. self.tempdir = tempfile.mkdtemp()
  134. self.cache = RerereCache(self.tempdir)
  135. def tearDown(self) -> None:
  136. """Clean up test fixtures."""
  137. import shutil
  138. shutil.rmtree(self.tempdir, ignore_errors=True)
  139. def test_record_conflict(self) -> None:
  140. """Test recording a conflict."""
  141. content = b"""line 1
  142. <<<<<<< ours
  143. our change
  144. =======
  145. their change
  146. >>>>>>> theirs
  147. line 2
  148. """
  149. conflict_id = self.cache.record_conflict(b"test.txt", content)
  150. self.assertIsNotNone(conflict_id)
  151. self.assertEqual(40, len(conflict_id)) # SHA-1 hash length
  152. def test_record_conflict_no_markers(self) -> None:
  153. """Test recording content without conflict markers."""
  154. content = b"line 1\nline 2\n"
  155. conflict_id = self.cache.record_conflict(b"test.txt", content)
  156. self.assertIsNone(conflict_id)
  157. def test_status_empty(self) -> None:
  158. """Test status with no conflicts."""
  159. status = self.cache.status()
  160. self.assertEqual([], status)
  161. def test_status_with_conflict(self) -> None:
  162. """Test status with a recorded conflict."""
  163. content = b"""<<<<<<< ours
  164. our change
  165. =======
  166. their change
  167. >>>>>>> theirs
  168. """
  169. conflict_id = self.cache.record_conflict(b"test.txt", content)
  170. status = self.cache.status()
  171. self.assertEqual(1, len(status))
  172. cid, has_resolution = status[0]
  173. self.assertEqual(conflict_id, cid)
  174. self.assertFalse(has_resolution)
  175. def test_has_resolution(self) -> None:
  176. """Test checking for resolution."""
  177. content = b"""<<<<<<< ours
  178. our change
  179. =======
  180. their change
  181. >>>>>>> theirs
  182. """
  183. conflict_id = self.cache.record_conflict(b"test.txt", content)
  184. self.assertIsNotNone(conflict_id)
  185. self.assertFalse(self.cache.has_resolution(conflict_id))
  186. def test_diff(self) -> None:
  187. """Test getting diff for a conflict."""
  188. content = b"""<<<<<<< ours
  189. our change
  190. =======
  191. their change
  192. >>>>>>> theirs
  193. """
  194. conflict_id = self.cache.record_conflict(b"test.txt", content)
  195. self.assertIsNotNone(conflict_id)
  196. preimage, postimage = self.cache.diff(conflict_id)
  197. self.assertIsNotNone(preimage)
  198. self.assertIsNone(postimage) # No resolution recorded yet
  199. def test_clear(self) -> None:
  200. """Test clearing all conflicts."""
  201. content = b"""<<<<<<< ours
  202. our change
  203. =======
  204. their change
  205. >>>>>>> theirs
  206. """
  207. self.cache.record_conflict(b"test.txt", content)
  208. status = self.cache.status()
  209. self.assertEqual(1, len(status))
  210. self.cache.clear()
  211. status = self.cache.status()
  212. self.assertEqual([], status)
  213. def test_forget(self) -> None:
  214. """Test forgetting a specific conflict."""
  215. content = b"""<<<<<<< ours
  216. our change
  217. =======
  218. their change
  219. >>>>>>> theirs
  220. """
  221. conflict_id = self.cache.record_conflict(b"test.txt", content)
  222. self.assertIsNotNone(conflict_id)
  223. self.cache.forget(conflict_id)
  224. status = self.cache.status()
  225. self.assertEqual([], status)
  226. class ConfigTests(unittest.TestCase):
  227. """Tests for rerere configuration functions."""
  228. def test_is_rerere_enabled_false_by_default(self) -> None:
  229. """Test that rerere is disabled by default."""
  230. from dulwich.config import ConfigDict
  231. config = ConfigDict()
  232. self.assertFalse(is_rerere_enabled(config))
  233. def test_is_rerere_enabled_true(self) -> None:
  234. """Test rerere enabled config."""
  235. from dulwich.config import ConfigDict
  236. config = ConfigDict()
  237. config.set((b"rerere",), b"enabled", b"true")
  238. self.assertTrue(is_rerere_enabled(config))
  239. def test_is_rerere_autoupdate_false_by_default(self) -> None:
  240. """Test that rerere.autoupdate is disabled by default."""
  241. from dulwich.config import ConfigDict
  242. config = ConfigDict()
  243. self.assertFalse(is_rerere_autoupdate(config))
  244. def test_is_rerere_autoupdate_true(self) -> None:
  245. """Test rerere.autoupdate enabled config."""
  246. from dulwich.config import ConfigDict
  247. config = ConfigDict()
  248. config.set((b"rerere",), b"autoupdate", b"true")
  249. self.assertTrue(is_rerere_autoupdate(config))