PageRenderTime 22ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/trac/versioncontrol/tests/diff.py

https://bitbucket.org/bluezoo/trac
Python | 262 lines | 245 code | 5 blank | 12 comment | 2 complexity | 976099b032e1b9a3e3815d4a4f2e9422 MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2004-2013 Edgewall Software
  4. # All rights reserved.
  5. #
  6. # This software is licensed as described in the file COPYING, which
  7. # you should have received as part of this distribution. The terms
  8. # are also available at http://trac.edgewall.org/wiki/TracLicense.
  9. #
  10. # This software consists of voluntary contributions made by many
  11. # individuals. For the exact contribution history, see the revision
  12. # history and logs, available at http://trac.edgewall.org/log/.
  13. from trac.versioncontrol import diff
  14. import unittest
  15. def get_opcodes(*args, **kwargs):
  16. for hunk in diff.get_filtered_hunks(*args, **kwargs):
  17. for opcode in hunk:
  18. yield opcode
  19. class DiffTestCase(unittest.TestCase):
  20. def testget_change_extent(self):
  21. self.assertEqual((3, 0), diff.get_change_extent('xxx', 'xxx'))
  22. self.assertEqual((0, 0), diff.get_change_extent('', 'xxx'))
  23. self.assertEqual((0, 0), diff.get_change_extent('xxx', ''))
  24. self.assertEqual((0, 0), diff.get_change_extent('xxx', 'yyy'))
  25. self.assertEqual((1, -1), diff.get_change_extent('xxx', 'xyx'))
  26. self.assertEqual((1, -1), diff.get_change_extent('xxx', 'xyyyx'))
  27. self.assertEqual((1, 0), diff.get_change_extent('xy', 'xzz'))
  28. self.assertEqual((1, -1), diff.get_change_extent('xyx', 'xzzx'))
  29. self.assertEqual((1, -1), diff.get_change_extent('xzzx', 'xyx'))
  30. def test_insert_blank_line(self):
  31. opcodes = get_opcodes(['A', 'B'], ['A', 'B', ''], ignore_blank_lines=0)
  32. self.assertEqual(('equal', 0, 2, 0, 2), opcodes.next())
  33. self.assertEqual(('insert', 2, 2, 2, 3), opcodes.next())
  34. self.assertRaises(StopIteration, opcodes.next)
  35. opcodes = get_opcodes(['A', 'B'], ['A', 'B', ''], ignore_blank_lines=1)
  36. self.assertEqual(('equal', 0, 2, 0, 3), opcodes.next())
  37. self.assertRaises(StopIteration, opcodes.next)
  38. opcodes = get_opcodes(['A'], ['A', 'B', ''], ignore_blank_lines=0)
  39. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  40. self.assertEqual(('insert', 1, 1, 1, 3), opcodes.next())
  41. self.assertRaises(StopIteration, opcodes.next)
  42. opcodes = get_opcodes(['A'], ['A', 'B', ''], ignore_blank_lines=1)
  43. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  44. self.assertEqual(('insert', 1, 1, 1, 3), opcodes.next())
  45. self.assertRaises(StopIteration, opcodes.next)
  46. def test_delete_blank_line(self):
  47. opcodes = get_opcodes(['A', 'B', ''], ['A', 'B'], ignore_blank_lines=0)
  48. self.assertEqual(('equal', 0, 2, 0, 2), opcodes.next())
  49. self.assertEqual(('delete', 2, 3, 2, 2), opcodes.next())
  50. self.assertRaises(StopIteration, opcodes.next)
  51. opcodes = get_opcodes(['A', 'B', ''], ['A', 'B'], ignore_blank_lines=1)
  52. self.assertEqual(('equal', 0, 3, 0, 2), opcodes.next())
  53. self.assertRaises(StopIteration, opcodes.next)
  54. opcodes = get_opcodes(['A', 'B', ''], ['A'], ignore_blank_lines=0)
  55. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  56. self.assertEqual(('delete', 1, 3, 1, 1), opcodes.next())
  57. self.assertRaises(StopIteration, opcodes.next)
  58. opcodes = get_opcodes(['A', 'B', ''], ['A'], ignore_blank_lines=1)
  59. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  60. self.assertEqual(('delete', 1, 3, 1, 1), opcodes.next())
  61. self.assertRaises(StopIteration, opcodes.next)
  62. def test_space_changes(self):
  63. opcodes = get_opcodes(['A', 'B b'], ['A', 'B b'],
  64. ignore_space_changes=0)
  65. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  66. self.assertEqual(('replace', 1, 2, 1, 2), opcodes.next())
  67. self.assertRaises(StopIteration, opcodes.next)
  68. opcodes = get_opcodes(['A', 'B b'], ['A', 'B b'],
  69. ignore_space_changes=1)
  70. self.assertEqual(('equal', 0, 2, 0, 2), opcodes.next())
  71. self.assertRaises(StopIteration, opcodes.next)
  72. def test_space_changes_2(self):
  73. left = """\
  74. try:
  75. try:
  76. func()
  77. commit()
  78. except:
  79. rollback()
  80. finally:
  81. cleanup()
  82. """
  83. left = left.splitlines()
  84. right = """\
  85. try:
  86. func()
  87. commit()
  88. except:
  89. rollback()
  90. finally:
  91. cleanup()
  92. """
  93. right = right.splitlines()
  94. opcodes = get_opcodes(left, right, ignore_space_changes=0)
  95. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  96. self.assertEqual(('replace', 1, 6, 1, 5), opcodes.next())
  97. self.assertEqual(('equal', 6, 8, 5, 7), opcodes.next())
  98. self.assertRaises(StopIteration, opcodes.next)
  99. opcodes = get_opcodes(left, right, ignore_space_changes=1)
  100. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  101. self.assertEqual(('delete', 1, 2, 1, 1), opcodes.next())
  102. self.assertEqual(('equal', 2, 4, 1, 3), opcodes.next())
  103. self.assertEqual(('replace', 4, 5, 3, 4), opcodes.next())
  104. self.assertEqual(('equal', 5, 8, 4, 7), opcodes.next())
  105. self.assertRaises(StopIteration, opcodes.next)
  106. def test_case_changes(self):
  107. opcodes = get_opcodes(['A', 'B b'], ['A', 'B B'], ignore_case=0)
  108. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  109. self.assertEqual(('replace', 1, 2, 1, 2), opcodes.next())
  110. self.assertRaises(StopIteration, opcodes.next)
  111. opcodes = get_opcodes(['A', 'B b'], ['A', 'B B'], ignore_case=1)
  112. self.assertEqual(('equal', 0, 2, 0, 2), opcodes.next())
  113. self.assertRaises(StopIteration, opcodes.next)
  114. def test_space_and_case_changes(self):
  115. opcodes = get_opcodes(['A', 'B b'], ['A', 'B B'],
  116. ignore_case=0, ignore_space_changes=0)
  117. self.assertEqual(('equal', 0, 1, 0, 1), opcodes.next())
  118. self.assertEqual(('replace', 1, 2, 1, 2), opcodes.next())
  119. self.assertRaises(StopIteration, opcodes.next)
  120. opcodes = get_opcodes(['A', 'B b'], ['A', 'B B'],
  121. ignore_case=1, ignore_space_changes=1)
  122. self.assertEqual(('equal', 0, 2, 0, 2), opcodes.next())
  123. self.assertRaises(StopIteration, opcodes.next)
  124. def test_grouped_opcodes_context1(self):
  125. groups = diff.get_filtered_hunks(
  126. ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'],
  127. ['A', 'B', 'C', 'd', 'e', 'f', 'G', 'H'], context=1)
  128. group = groups.next()
  129. self.assertRaises(StopIteration, groups.next)
  130. self.assertEqual(('equal', 2, 3, 2, 3), group[0])
  131. self.assertEqual(('replace', 3, 6, 3, 6), group[1])
  132. self.assertEqual(('equal', 6, 7, 6, 7), group[2])
  133. def test_grouped_opcodes_context1_ignorecase(self):
  134. old = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
  135. new = ['X', 'B', 'C', 'd', 'e', 'f', 'G', 'Y']
  136. groups = diff.get_filtered_hunks(old, new, context=1, ignore_case=1)
  137. group = groups.next()
  138. self.assertEqual([('replace', 0, 1, 0, 1), ('equal', 1, 2, 1, 2)],
  139. group)
  140. group = groups.next()
  141. self.assertRaises(StopIteration, groups.next)
  142. self.assertEqual([('equal', 6, 7, 6, 7), ('replace', 7, 8, 7, 8)],
  143. group)
  144. def test_grouped_opcodes_full_context(self):
  145. old = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
  146. new = ['X', 'B', 'C', 'd', 'e', 'f', 'G', 'Y']
  147. groups = diff.get_filtered_hunks(old, new, context=None)
  148. group = groups.next()
  149. self.assertRaises(StopIteration, groups.next)
  150. self.assertEqual([
  151. ('replace', 0, 1, 0, 1),
  152. ('equal', 1, 3, 1, 3),
  153. ('replace', 3, 6, 3, 6),
  154. ('equal', 6, 7, 6, 7),
  155. ('replace', 7, 8, 7, 8),
  156. ], group)
  157. groups = diff.get_filtered_hunks(old, new, context=None, ignore_case=1)
  158. group = groups.next()
  159. self.assertRaises(StopIteration, groups.next)
  160. self.assertEqual([
  161. ('replace', 0, 1, 0, 1),
  162. ('equal', 1, 7, 1, 7),
  163. ('replace', 7, 8, 7, 8),
  164. ], group)
  165. def test_grouped_opcodes_insert_blank_line_at_top(self):
  166. """
  167. Regression test for #2090. Make sure that the equal block following an
  168. insert at the top of a file is correct.
  169. """
  170. groups = diff.get_filtered_hunks(['B', 'C', 'D', 'E', 'F', 'G'],
  171. ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
  172. context=3)
  173. self.assertEqual([('insert', 0, 0, 0, 1), ('equal', 0, 3, 1, 4)],
  174. groups.next())
  175. self.assertRaises(StopIteration, groups.next)
  176. def test_unified_diff_no_context(self):
  177. diff_lines = list(diff.unified_diff(['a'], ['b']))
  178. self.assertEqual(['@@ -1,1 +1,1 @@', '-a', '+b'], diff_lines)
  179. def test_quotes_not_marked_up(self):
  180. """Make sure that the escape calls leave quotes along, we don't need
  181. to escape them."""
  182. changes = diff.diff_blocks(['ab'], ['a"b'])
  183. self.assertEqual(len(changes), 1)
  184. blocks = changes[0]
  185. self.assertEqual(len(blocks), 1)
  186. block = blocks[0]
  187. self.assertEqual(block['type'], 'mod')
  188. self.assertEqual(str(block['base']['lines'][0]), 'a<del></del>b')
  189. self.assertEqual(str(block['changed']['lines'][0]), 'a<ins>"</ins>b')
  190. def test_whitespace_marked_up1(self):
  191. """Regression test for #5795"""
  192. changes = diff.diff_blocks(['*a'], [' *a'])
  193. block = changes[0][0]
  194. self.assertEqual(block['type'], 'mod')
  195. self.assertEqual(str(block['base']['lines'][0]), '<del></del>*a')
  196. self.assertEqual(str(block['changed']['lines'][0]),
  197. '<ins>&nbsp;</ins>*a')
  198. def test_whitespace_marked_up2(self):
  199. """Related to #5795"""
  200. changes = diff.diff_blocks([' a'], [' b'])
  201. block = changes[0][0]
  202. self.assertEqual(block['type'], 'mod')
  203. self.assertEqual(str(block['base']['lines'][0]),
  204. '&nbsp; &nbsp;<del>a</del>')
  205. self.assertEqual(str(block['changed']['lines'][0]),
  206. '&nbsp; &nbsp;<ins>b</ins>')
  207. def test_whitespace_marked_up3(self):
  208. """Related to #5795"""
  209. changes = diff.diff_blocks(['a '], ['b '])
  210. block = changes[0][0]
  211. self.assertEqual(block['type'], 'mod')
  212. self.assertEqual(str(block['base']['lines'][0]),
  213. '<del>a</del>&nbsp; &nbsp;')
  214. self.assertEqual(str(block['changed']['lines'][0]),
  215. '<ins>b</ins>&nbsp; &nbsp;')
  216. def test_expandtabs_works_right(self):
  217. """Regression test for #4557"""
  218. changes = diff.diff_blocks(['aa\tb'], ['aaxb'])
  219. block = changes[0][0]
  220. self.assertEqual(block['type'], 'mod')
  221. self.assertEqual(str(block['base']['lines'][0]),
  222. 'aa<del>&nbsp; &nbsp; &nbsp; </del>b')
  223. self.assertEqual(str(block['changed']['lines'][0]),
  224. 'aa<ins>x</ins>b')
  225. def test_suite():
  226. return unittest.makeSuite(DiffTestCase)
  227. if __name__ == '__main__':
  228. unittest.main(defaultTest='test_suite')