test_cdiff.py 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """Unit test for cdiff"""
  4. import sys
  5. if sys.hexversion < 0x02050000:
  6. raise SystemExit("*** Requires python >= 2.5.0") # pragma: no cover
  7. import unittest
  8. import tempfile
  9. import subprocess
  10. import os
  11. sys.path.insert(0, '')
  12. import cdiff
  13. class Sequential(object):
  14. """A non-seekable iterator, mock of file object"""
  15. def __init__(self, items):
  16. self._items = items
  17. self._index = 0
  18. def __iter__(self):
  19. while True:
  20. try:
  21. item = self._items[self._index]
  22. except IndexError:
  23. raise StopIteration
  24. yield item
  25. self._index += 1
  26. def readline(self):
  27. try:
  28. item = self._items[self._index]
  29. except IndexError:
  30. return ''
  31. self._index += 1
  32. return item
  33. class PatchStreamTest(unittest.TestCase):
  34. def test_is_empty(self):
  35. stream = cdiff.PatchStream(Sequential([]))
  36. self.assertTrue(stream.is_empty())
  37. stream = cdiff.PatchStream(Sequential(['hello', 'world']))
  38. self.assertFalse(stream.is_empty())
  39. def test_read_stream_header(self):
  40. stream = cdiff.PatchStream(Sequential([]))
  41. self.assertEqual(stream.read_stream_header(1), [])
  42. items = ['hello', 'world', 'again']
  43. stream = cdiff.PatchStream(Sequential(items))
  44. self.assertEqual(stream.read_stream_header(2), items[:2])
  45. stream = cdiff.PatchStream(Sequential(items))
  46. self.assertEqual(stream.read_stream_header(4), items[:])
  47. def test_iter_after_read_stream_header(self):
  48. items = ['hello', 'world', 'again', 'and', 'again']
  49. stream = cdiff.PatchStream(Sequential(items))
  50. _ = stream.read_stream_header(2)
  51. out = list(stream)
  52. self.assertEqual(out, items)
  53. class HunkTest(unittest.TestCase):
  54. def test_get_old_text(self):
  55. hunk = cdiff.Hunk([], '@@ -1,2 +1,2 @@', (1, 2), (1, 2))
  56. hunk.append(('-', 'foo\n'))
  57. hunk.append(('+', 'bar\n'))
  58. hunk.append((' ', 'common\n'))
  59. self.assertEqual(hunk._get_old_text(), ['foo\n', 'common\n'])
  60. def test_get_new_text(self):
  61. hunk = cdiff.Hunk([], '@@ -1,2 +1,2 @@', (1, 2), (1, 2))
  62. hunk.append(('-', 'foo\n'))
  63. hunk.append(('+', 'bar\n'))
  64. hunk.append((' ', 'common\n'))
  65. self.assertEqual(hunk._get_new_text(), ['bar\n', 'common\n'])
  66. class DiffTest(unittest.TestCase):
  67. def _init_diff(self):
  68. """Return a minimal diff contains all required samples
  69. header
  70. --- old
  71. +++ new
  72. hunk header
  73. @@ -1,4 +1,4 @@
  74. -hhello
  75. +helloo
  76. +spammm
  77. world
  78. -garb
  79. -Again
  80. +again
  81. """
  82. hunk = cdiff.Hunk(['hunk header\n'], '@@ -1,4 +1,4 @@\n',
  83. (1, 4), (1, 4))
  84. hunk.append(('-', 'hhello\n'))
  85. hunk.append(('+', 'helloo\n'))
  86. hunk.append(('+', 'spammm\n'))
  87. hunk.append((' ', 'world\n'))
  88. hunk.append(('-', 'garb\n'))
  89. hunk.append(('-', 'Again\n'))
  90. hunk.append(('+', 'again\n'))
  91. diff = cdiff.Diff(['header\n'], '--- old\n', '+++ new\n', [hunk])
  92. return diff
  93. def test_markup_mix(self):
  94. line = 'foo \x00-del\x01 \x00+add\x01 \x00^chg\x01 bar'
  95. base_color = 'red'
  96. diff = cdiff.Diff(None, None, None, None)
  97. self.assertEqual(
  98. diff._markup_mix(line, base_color),
  99. '\x1b[31mfoo \x1b[7m\x1b[31mdel\x1b[0m\x1b[31m '
  100. '\x1b[7m\x1b[31madd\x1b[0m\x1b[31m '
  101. '\x1b[4m\x1b[31mchg\x1b[0m\x1b[31m bar\x1b[0m')
  102. def test_markup_traditional_hunk_header(self):
  103. hunk = cdiff.Hunk(['hunk header\n'], '@@ -0 +0 @@\n', (0, 0), (0, 0))
  104. diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
  105. out = list(diff.markup_traditional())
  106. self.assertEqual(len(out), 4)
  107. self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
  108. self.assertEqual(out[1], '\x1b[33m+++ new\n\x1b[0m')
  109. self.assertEqual(out[2], '\x1b[1;36mhunk header\n\x1b[0m')
  110. self.assertEqual(out[3], '\x1b[1;34m@@ -0 +0 @@\n\x1b[0m')
  111. def test_markup_traditional_old_changed(self):
  112. hunk = cdiff.Hunk([], '@@ -1 +0,0 @@\n', (1, 0), (0, 0))
  113. hunk.append(('-', 'spam\n'))
  114. diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
  115. out = list(diff.markup_traditional())
  116. self.assertEqual(len(out), 4)
  117. self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
  118. self.assertEqual(out[1], '\x1b[33m+++ new\n\x1b[0m')
  119. self.assertEqual(out[2], '\x1b[1;34m@@ -1 +0,0 @@\n\x1b[0m')
  120. self.assertEqual(out[3], '\x1b[1;31m-spam\n\x1b[0m')
  121. def test_markup_traditional_new_changed(self):
  122. hunk = cdiff.Hunk([], '@@ -0,0 +1 @@\n', (0, 0), (1, 0))
  123. hunk.append(('+', 'spam\n'))
  124. diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
  125. out = list(diff.markup_traditional())
  126. self.assertEqual(len(out), 4)
  127. self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
  128. self.assertEqual(out[1], '\x1b[33m+++ new\n\x1b[0m')
  129. self.assertEqual(out[2], '\x1b[1;34m@@ -0,0 +1 @@\n\x1b[0m')
  130. self.assertEqual(out[3], '\x1b[1;32m+spam\n\x1b[0m')
  131. def test_markup_traditional_both_changed(self):
  132. hunk = cdiff.Hunk([], '@@ -1,2 +1,2 @@\n', (1, 2), (1, 2))
  133. hunk.append(('-', 'hella\n'))
  134. hunk.append(('+', 'hello\n'))
  135. hunk.append((' ', 'common\n'))
  136. diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
  137. out = list(diff.markup_traditional())
  138. self.assertEqual(len(out), 6)
  139. self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
  140. self.assertEqual(out[1], '\x1b[33m+++ new\n\x1b[0m')
  141. self.assertEqual(out[2], '\x1b[1;34m@@ -1,2 +1,2 @@\n\x1b[0m')
  142. self.assertEqual(
  143. out[3],
  144. '\x1b[1;31m-\x1b[0m\x1b[31mhell'
  145. '\x1b[4m\x1b[31ma\x1b[0m\x1b[31m\n\x1b[0m')
  146. self.assertEqual(
  147. out[4],
  148. '\x1b[1;32m+\x1b[0m\x1b[32mhell'
  149. '\x1b[4m\x1b[32mo\x1b[0m\x1b[32m\n\x1b[0m')
  150. self.assertEqual(out[5], '\x1b[0m common\n\x1b[0m')
  151. def test_markup_side_by_side_padded(self):
  152. diff = self._init_diff()
  153. out = list(diff.markup_side_by_side(7))
  154. self.assertEqual(len(out), 10)
  155. sys.stdout.write('\n')
  156. for markup in out:
  157. sys.stdout.write(markup)
  158. self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
  159. self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
  160. self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
  161. self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
  162. self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
  163. self.assertEqual(
  164. out[5],
  165. '\x1b[33m1\x1b[0m '
  166. '\x1b[31m\x1b[7m\x1b[31mh\x1b[0m\x1b[31mhello\x1b[0m '
  167. '\x1b[0m\x1b[33m1\x1b[0m '
  168. '\x1b[32mhello\x1b[7m\x1b[32mo\x1b[0m\x1b[32m\x1b[0m\n')
  169. self.assertEqual(
  170. out[6],
  171. '\x1b[33m '
  172. '\x1b[0m '
  173. '\x1b[0m\x1b[33m2\x1b[0m '
  174. '\x1b[1;32mspammm\x1b[0m\n')
  175. self.assertEqual(
  176. out[7],
  177. '\x1b[33m2\x1b[0m '
  178. '\x1b[0mworld\x1b[0m '
  179. '\x1b[0m\x1b[33m3\x1b[0m '
  180. '\x1b[0mworld\x1b[0m\n')
  181. self.assertEqual(
  182. out[8],
  183. '\x1b[33m3\x1b[0m '
  184. '\x1b[1;31mgarb\x1b[0m '
  185. '\x1b[0m\x1b[33m '
  186. '\x1b[0m \n')
  187. self.assertEqual(
  188. out[9],
  189. '\x1b[33m4\x1b[0m '
  190. '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m '
  191. '\x1b[0m\x1b[33m4\x1b[0m '
  192. '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
  193. def test_markup_side_by_side_neg_width(self):
  194. diff = self._init_diff()
  195. out = list(diff.markup_side_by_side(-1))
  196. self.assertEqual(len(out), 10)
  197. self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
  198. self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
  199. self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
  200. self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
  201. self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
  202. self.assertEqual(
  203. out[5],
  204. '\x1b[33m1\x1b[0m '
  205. '\x1b[31m\x1b[7m\x1b[31mh\x1b[0m\x1b[31mhello\x1b[0m ' +
  206. (' ' * 74) +
  207. '\x1b[0m\x1b[33m1\x1b[0m '
  208. '\x1b[32mhello\x1b[7m\x1b[32mo\x1b[0m\x1b[32m\x1b[0m\n')
  209. self.assertEqual(
  210. out[6],
  211. '\x1b[33m '
  212. '\x1b[0m ' + (' ' * 80) +
  213. '\x1b[0m\x1b[33m2\x1b[0m '
  214. '\x1b[1;32mspammm\x1b[0m\n')
  215. self.assertEqual(
  216. out[7],
  217. '\x1b[33m2\x1b[0m '
  218. '\x1b[0mworld\x1b[0m ' + (' ' * 75) +
  219. '\x1b[0m\x1b[33m3\x1b[0m '
  220. '\x1b[0mworld\x1b[0m\n')
  221. self.assertEqual(
  222. out[8],
  223. '\x1b[33m3\x1b[0m '
  224. '\x1b[1;31mgarb\x1b[0m '
  225. '\x1b[0m\x1b[33m '
  226. '\x1b[0m \n')
  227. self.assertEqual(
  228. out[9],
  229. '\x1b[33m4\x1b[0m '
  230. '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m ' +
  231. (' ' * 75) +
  232. '\x1b[0m\x1b[33m4\x1b[0m '
  233. '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
  234. def test_markup_side_by_side_off_by_one(self):
  235. diff = self._init_diff()
  236. out = list(diff.markup_side_by_side(6))
  237. self.assertEqual(len(out), 10)
  238. sys.stdout.write('\n')
  239. for markup in out:
  240. sys.stdout.write(markup)
  241. self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
  242. self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
  243. self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
  244. self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
  245. self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
  246. self.assertEqual(
  247. out[5],
  248. '\x1b[33m1\x1b[0m '
  249. '\x1b[31m\x1b[7m\x1b[31mh\x1b[0m\x1b[31mhello\x1b[0m '
  250. '\x1b[0m\x1b[33m1\x1b[0m '
  251. '\x1b[32mhello\x1b[7m\x1b[32mo\x1b[0m\n')
  252. self.assertEqual(
  253. out[6],
  254. '\x1b[33m \x1b[0m '
  255. '\x1b[0m\x1b[33m2\x1b[0m '
  256. '\x1b[1;32mspammm\x1b[0m\n')
  257. self.assertEqual(
  258. out[7],
  259. '\x1b[33m2\x1b[0m '
  260. '\x1b[0mworld\x1b[0m '
  261. '\x1b[0m\x1b[33m3\x1b[0m '
  262. '\x1b[0mworld\x1b[0m\n')
  263. self.assertEqual(
  264. out[8],
  265. '\x1b[33m3\x1b[0m '
  266. '\x1b[1;31mgarb\x1b[0m '
  267. '\x1b[0m\x1b[33m '
  268. '\x1b[0m \n')
  269. self.assertEqual(
  270. out[9],
  271. '\x1b[33m4\x1b[0m '
  272. '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m '
  273. '\x1b[0m\x1b[33m4\x1b[0m '
  274. '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
  275. def test_markup_side_by_side_wrapped(self):
  276. diff = self._init_diff()
  277. out = list(diff.markup_side_by_side(5))
  278. self.assertEqual(len(out), 10)
  279. sys.stdout.write('\n')
  280. for markup in out:
  281. sys.stdout.write(markup)
  282. self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
  283. self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
  284. self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
  285. self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
  286. self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
  287. self.assertEqual(
  288. out[5],
  289. '\x1b[33m1\x1b[0m '
  290. '\x1b[31m\x1b[7m\x1b[31mh\x1b[0m\x1b[31mhel\x1b[0m\x1b[1;35m>\x1b[0m '
  291. '\x1b[0m\x1b[33m1\x1b[0m '
  292. '\x1b[32mhell\x1b[0m\x1b[1;35m>\x1b[0m\n')
  293. self.assertEqual(
  294. out[6],
  295. '\x1b[33m \x1b[0m '
  296. '\x1b[0m\x1b[33m2\x1b[0m '
  297. ''
  298. '\x1b[1;32mspam\x1b[0m\x1b[1;35m>\x1b[0m\n')
  299. self.assertEqual(
  300. out[7],
  301. '\x1b[33m2\x1b[0m '
  302. '\x1b[0mworld\x1b[0m '
  303. '\x1b[0m\x1b[33m3\x1b[0m '
  304. '\x1b[0mworld\x1b[0m\n')
  305. self.assertEqual(
  306. out[8],
  307. '\x1b[33m3\x1b[0m '
  308. '\x1b[1;31mgarb\x1b[0m '
  309. '\x1b[0m\x1b[33m '
  310. '\x1b[0m \n')
  311. self.assertEqual(
  312. out[9],
  313. '\x1b[33m4\x1b[0m '
  314. '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m '
  315. '\x1b[0m\x1b[33m4\x1b[0m '
  316. '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
  317. class UnifiedDiffTest(unittest.TestCase):
  318. diff = cdiff.UnifiedDiff(None, None, None, None)
  319. def test_is_hunk_meta_normal(self):
  320. self.assertTrue(self.diff.is_hunk_meta('@@ -1 +1 @@'))
  321. self.assertTrue(self.diff.is_hunk_meta('@@ -3,7 +3,6 @@'))
  322. self.assertTrue(self.diff.is_hunk_meta('@@ -3,7 +3,6 @@ class Foo'))
  323. self.assertTrue(self.diff.is_hunk_meta('@@ -3,7 +3,6 @@ class Foo\n'))
  324. self.assertTrue(
  325. self.diff.is_hunk_meta('@@ -3,7 +3,6 @@ class Foo\r\n'))
  326. def test_is_hunk_meta_svn_prop(self):
  327. self.assertTrue(self.diff.is_hunk_meta('## -0,0 +1 ##'))
  328. self.assertTrue(self.diff.is_hunk_meta('## -0,0 +1 ##\n'))
  329. self.assertTrue(self.diff.is_hunk_meta('## -0,0 +1 ##\r\n'))
  330. def test_is_hunk_meta_neg(self):
  331. self.assertFalse(self.diff.is_hunk_meta('@@ -1 + @@'))
  332. self.assertFalse(self.diff.is_hunk_meta('@@ -this is not a hunk meta'))
  333. self.assertFalse(self.diff.is_hunk_meta('## -this is not either'))
  334. def test_parse_hunk_meta_normal(self):
  335. self.assertEqual(self.diff.parse_hunk_meta('@@ -3,7 +3,6 @@'),
  336. ((3, 7), (3, 6)))
  337. def test_parse_hunk_meta_missing(self):
  338. self.assertEqual(self.diff.parse_hunk_meta('@@ -3 +3,6 @@'),
  339. ((3, 0), (3, 6)))
  340. self.assertEqual(self.diff.parse_hunk_meta('@@ -3,7 +3 @@'),
  341. ((3, 7), (3, 0)))
  342. self.assertEqual(self.diff.parse_hunk_meta('@@ -3 +3 @@'),
  343. ((3, 0), (3, 0)))
  344. def test_parse_hunk_meta_svn_prop(self):
  345. self.assertEqual(self.diff.parse_hunk_meta('## -0,0 +1 ##'),
  346. ((0, 0), (1, 0)))
  347. def test_is_old(self):
  348. self.assertTrue(self.diff.is_old('-hello world'))
  349. self.assertTrue(self.diff.is_old('----')) # yaml
  350. def test_is_old_neg(self):
  351. self.assertFalse(self.diff.is_old('--- considered as old path'))
  352. self.assertFalse(self.diff.is_old('-' * 72)) # svn log --diff
  353. def test_is_new(self):
  354. self.assertTrue(self.diff.is_new('+hello world'))
  355. self.assertTrue(self.diff.is_new('++++hello world'))
  356. def test_is_new_neg(self):
  357. self.assertFalse(self.diff.is_new('+++ considered as new path'))
  358. class DiffParserTest(unittest.TestCase):
  359. def test_type_detect_unified(self):
  360. patch = """\
  361. spam
  362. --- a
  363. +++ b
  364. @@ -1,2 +1,2 @@
  365. """
  366. items = patch.splitlines(True)
  367. stream = cdiff.PatchStream(Sequential(items))
  368. parser = cdiff.DiffParser(stream)
  369. self.assertEqual(parser._type, 'unified')
  370. # Note @unittest.skip() not available for python < 2.7
  371. def SKIP_test_type_detect_context(self):
  372. patch = """\
  373. *** /path/to/original timestamp
  374. --- /path/to/new timestamp
  375. ***************
  376. *** 1,1 ****
  377. --- 1,2 ----
  378. + This is an important
  379. This part of the
  380. """
  381. items = patch.splitlines(True)
  382. stream = cdiff.PatchStream(Sequential(items))
  383. parser = cdiff.DiffParser(stream)
  384. self.assertEqual(parser._type, 'context')
  385. def test_type_detect_neg(self):
  386. patch = """\
  387. spam
  388. --- a
  389. spam
  390. +++ b
  391. """
  392. items = patch.splitlines(True)
  393. stream = cdiff.PatchStream(Sequential(items))
  394. parser = cdiff.DiffParser(stream)
  395. self.assertEqual(parser._type, 'unified')
  396. def test_parse_invalid_hunk_meta(self):
  397. patch = """\
  398. spam
  399. --- a
  400. +++ b
  401. spam
  402. @@ -a,a +0 @@
  403. """
  404. items = patch.splitlines(True)
  405. stream = cdiff.PatchStream(Sequential(items))
  406. parser = cdiff.DiffParser(stream)
  407. self.assertRaises(RuntimeError, list, parser.get_diff_generator())
  408. def test_parse_dangling_header(self):
  409. patch = """\
  410. --- a
  411. +++ b
  412. @@ -1,2 +1,2 @@
  413. -foo
  414. +bar
  415. common
  416. spam
  417. """
  418. items = patch.splitlines(True)
  419. stream = cdiff.PatchStream(Sequential(items))
  420. parser = cdiff.DiffParser(stream)
  421. out = list(parser.get_diff_generator())
  422. self.assertEqual(len(out), 2)
  423. self.assertEqual(len(out[1]._headers), 1)
  424. self.assertEqual(out[1]._headers[0], 'spam\n')
  425. self.assertEqual(out[1]._old_path, '')
  426. self.assertEqual(out[1]._new_path, '')
  427. self.assertEqual(len(out[1]._hunks), 0)
  428. def test_parse_missing_new_path(self):
  429. patch = """\
  430. --- a
  431. +++ b
  432. @@ -1,2 +1,2 @@
  433. -foo
  434. +bar
  435. common
  436. --- c
  437. """
  438. items = patch.splitlines(True)
  439. stream = cdiff.PatchStream(Sequential(items))
  440. parser = cdiff.DiffParser(stream)
  441. self.assertRaises(AssertionError, list, parser.get_diff_generator())
  442. def test_parse_missing_hunk_meta(self):
  443. patch = """\
  444. --- a
  445. +++ b
  446. @@ -1,2 +1,2 @@
  447. -foo
  448. +bar
  449. common
  450. --- c
  451. +++ d
  452. """
  453. items = patch.splitlines(True)
  454. stream = cdiff.PatchStream(Sequential(items))
  455. parser = cdiff.DiffParser(stream)
  456. out = list(parser.get_diff_generator())
  457. self.assertEqual(len(out), 2)
  458. self.assertEqual(len(out[1]._headers), 0)
  459. self.assertEqual(out[1]._old_path, '--- c\n')
  460. self.assertEqual(out[1]._new_path, '+++ d\n')
  461. self.assertEqual(len(out[1]._hunks), 0)
  462. def test_parse_missing_hunk_list(self):
  463. patch = """\
  464. --- a
  465. +++ b
  466. @@ -1,2 +1,2 @@
  467. -foo
  468. +bar
  469. common
  470. --- c
  471. +++ d
  472. @@ -1,2 +1,2 @@
  473. """
  474. items = patch.splitlines(True)
  475. stream = cdiff.PatchStream(Sequential(items))
  476. parser = cdiff.DiffParser(stream)
  477. self.assertRaises(AssertionError, list, parser.get_diff_generator())
  478. def test_parse_only_in_dir(self):
  479. patch = """\
  480. --- a
  481. +++ b
  482. @@ -1,2 +1,2 @@
  483. -foo
  484. +bar
  485. common
  486. Only in foo: foo
  487. --- c
  488. +++ d
  489. @@ -1,2 +1,2 @@
  490. -foo
  491. +bar
  492. common
  493. """
  494. items = patch.splitlines(True)
  495. stream = cdiff.PatchStream(Sequential(items))
  496. parser = cdiff.DiffParser(stream)
  497. out = list(parser.get_diff_generator())
  498. self.assertEqual(len(out), 3)
  499. self.assertEqual(len(out[1]._hunks), 0)
  500. self.assertEqual(out[1]._headers, ['Only in foo: foo\n'])
  501. self.assertEqual(len(out[2]._hunks), 1)
  502. self.assertEqual(len(out[2]._hunks[0]._hunk_list), 3)
  503. def test_parse_only_in_dir_at_last(self):
  504. patch = """\
  505. --- a
  506. +++ b
  507. @@ -1,2 +1,2 @@
  508. -foo
  509. +bar
  510. common
  511. Only in foo: foo
  512. """
  513. items = patch.splitlines(True)
  514. stream = cdiff.PatchStream(Sequential(items))
  515. parser = cdiff.DiffParser(stream)
  516. out = list(parser.get_diff_generator())
  517. self.assertEqual(len(out), 2)
  518. self.assertEqual(len(out[1]._hunks), 0)
  519. self.assertEqual(out[1]._headers, ['Only in foo: foo\n'])
  520. def test_parse_binary_differ_diff_ru(self):
  521. patch = """\
  522. --- a
  523. +++ b
  524. @@ -1,2 +1,2 @@
  525. -foo
  526. +bar
  527. common
  528. Binary files a/1.pdf and b/1.pdf differ
  529. --- c
  530. +++ d
  531. @@ -1,2 +1,2 @@
  532. -foo
  533. +bar
  534. common
  535. """
  536. items = patch.splitlines(True)
  537. stream = cdiff.PatchStream(Sequential(items))
  538. parser = cdiff.DiffParser(stream)
  539. out = list(parser.get_diff_generator())
  540. self.assertEqual(len(out), 3)
  541. self.assertEqual(len(out[1]._hunks), 0)
  542. self.assertEqual(out[1]._old_path, '')
  543. self.assertEqual(out[1]._new_path, '')
  544. self.assertEqual(len(out[1]._headers), 1)
  545. self.assertTrue(out[1]._headers[0].startswith('Binary files'))
  546. self.assertEqual(len(out[2]._hunks), 1)
  547. self.assertEqual(len(out[2]._hunks[0]._hunk_list), 3)
  548. def test_parse_binary_differ_git(self):
  549. patch = """\
  550. diff --git a/foo b/foo
  551. index 529d8a3..ad71911 100755
  552. --- a/foo
  553. +++ b/foo
  554. @@ -1,2 +1,2 @@
  555. -foo
  556. +bar
  557. common
  558. diff --git a/example.pdf b/example.pdf
  559. index 1eacfd8..3696851 100644
  560. Binary files a/example.pdf and b/example.pdf differ
  561. diff --git a/bar b/bar
  562. index 529e8a3..ad71921 100755
  563. --- a/bar
  564. +++ b/bar
  565. @@ -1,2 +1,2 @@
  566. -foo
  567. +bar
  568. common
  569. """
  570. items = patch.splitlines(True)
  571. stream = cdiff.PatchStream(Sequential(items))
  572. parser = cdiff.DiffParser(stream)
  573. out = list(parser.get_diff_generator())
  574. self.assertEqual(len(out), 3)
  575. self.assertEqual(len(out[1]._hunks), 0)
  576. self.assertEqual(out[1]._old_path, '')
  577. self.assertEqual(out[1]._new_path, '')
  578. self.assertEqual(len(out[1]._headers), 3)
  579. self.assertTrue(out[1]._headers[2].startswith('Binary files'))
  580. self.assertEqual(len(out[2]._hunks), 1)
  581. self.assertEqual(len(out[2]._hunks[0]._hunk_list), 3)
  582. def test_parse_svn_prop(self):
  583. patch = """\
  584. --- a
  585. +++ b
  586. Added: svn:executable
  587. ## -0,0 +1 ##
  588. +*
  589. \\ No newline at end of property
  590. Added: svn:keywords
  591. ## -0,0 +1 ##
  592. +Id
  593. """
  594. items = patch.splitlines(True)
  595. stream = cdiff.PatchStream(Sequential(items))
  596. parser = cdiff.DiffParser(stream)
  597. out = list(parser.get_diff_generator())
  598. self.assertEqual(len(out), 1)
  599. self.assertEqual(len(out[0]._hunks), 2)
  600. hunk = out[0]._hunks[1]
  601. self.assertEqual(hunk._hunk_headers, ['Added: svn:keywords\n'])
  602. self.assertEqual(hunk._hunk_list, [('+', 'Id\n')])
  603. class MainTest(unittest.TestCase):
  604. def setUp(self):
  605. self._cwd = os.getcwd()
  606. self._ws = tempfile.mkdtemp(prefix='test_cdiff')
  607. self._non_ws = tempfile.mkdtemp(prefix='test_cdiff')
  608. cmd = ('cd %s; git init; git config user.name me; '
  609. 'git config user.email me@example.org') % self._ws
  610. subprocess.call(cmd, shell=True, stdout=subprocess.PIPE)
  611. self._change_file('init')
  612. def tearDown(self):
  613. os.chdir(self._cwd)
  614. cmd = ['/bin/rm', '-rf', self._ws, self._non_ws]
  615. subprocess.call(cmd)
  616. def _change_file(self, text):
  617. cmd = ['/bin/sh', '-c',
  618. 'cd %s; echo "%s" > foo' % (self._ws, text)]
  619. subprocess.call(cmd)
  620. def _commit_file(self):
  621. cmd = ['/bin/sh', '-c',
  622. 'cd %s; git add foo; git commit foo -m update' % self._ws]
  623. subprocess.call(cmd, stdout=subprocess.PIPE)
  624. def test_read_diff(self):
  625. sys.argv = sys.argv[:1]
  626. self._change_file('read_diff')
  627. os.chdir(self._ws)
  628. ret = cdiff.main()
  629. os.chdir(self._cwd)
  630. self.assertEqual(ret, 0)
  631. def test_read_diff_neg(self):
  632. sys.argv = sys.argv[:1]
  633. os.chdir(self._non_ws)
  634. ret = cdiff.main()
  635. os.chdir(self._cwd)
  636. self.assertNotEqual(ret, 0)
  637. def test_read_log(self):
  638. sys.argv = [sys.argv[0], '--log']
  639. self._change_file('read_log')
  640. self._commit_file()
  641. os.chdir(self._ws)
  642. ret = cdiff.main()
  643. os.chdir(self._cwd)
  644. self.assertEqual(ret, 0)
  645. def test_read_log_neg(self):
  646. sys.argv = [sys.argv[0], '--log']
  647. os.chdir(self._non_ws)
  648. ret = cdiff.main()
  649. os.chdir(self._cwd)
  650. self.assertNotEqual(ret, 0)
  651. if __name__ == '__main__':
  652. unittest.main()
  653. # vim:set et sts=4 sw=4 tw=80: