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