git_footers_test.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #!/usr/bin/env vpython3
  2. """Tests for git_footers."""
  3. from io import StringIO
  4. import json
  5. import os
  6. import sys
  7. import unittest
  8. from unittest import mock
  9. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  10. import gclient_utils
  11. import git_footers
  12. class GitFootersTest(unittest.TestCase):
  13. _message = """
  14. This is my commit message. There are many like it, but this one is mine.
  15. My commit message is my best friend. It is my life.
  16. """
  17. _position = 'refs/heads/main@{#292272}'
  18. _position_footer = 'Cr-Commit-Position: %s\n' % _position
  19. def testFootersBasic(self):
  20. self.assertEqual(
  21. git_footers.split_footers('Not-A: footer'),
  22. (['Not-A: footer'], [], []))
  23. self.assertEqual(
  24. git_footers.split_footers('Header\n\nActual: footer'),
  25. (['Header', ''], ['Actual: footer'], [('Actual', 'footer')]))
  26. self.assertEqual(
  27. git_footers.split_footers('\nActual: footer'),
  28. ([''], ['Actual: footer'], [('Actual', 'footer')]))
  29. self.assertEqual(
  30. git_footers.split_footers('H\n\nBug:\nAlso: footer'),
  31. (['H', ''], ['Bug:', 'Also: footer'],
  32. [('Bug', ''), ('Also', 'footer')]))
  33. self.assertEqual(git_footers.split_footers('H\n\nBug: '),
  34. (['H', ''], ['Bug:'], [('Bug', '')]))
  35. self.assertEqual(git_footers.split_footers('H\n\nBug: 1234 '),
  36. (['H', ''], ['Bug: 1234'], [('Bug', '1234')]))
  37. self.assertEqual(
  38. git_footers.split_footers('H\n\nBug: 1234\nChange-Id: Ib4321 '),
  39. (['H', ''], ['Bug: 1234', 'Change-Id: Ib4321'], [('Bug', '1234'),
  40. ('Change-Id', 'Ib4321')
  41. ]))
  42. self.assertEqual(
  43. git_footers.parse_footers(self._message), {})
  44. self.assertEqual(
  45. git_footers.parse_footers(self._message + self._position_footer),
  46. { 'Cr-Commit-Position': [ self._position ] })
  47. self.assertEqual(
  48. git_footers.parse_footers(self._message + self._position_footer
  49. + self._position_footer),
  50. { 'Cr-Commit-Position': [ self._position, self._position ] })
  51. self.assertEqual(
  52. git_footers.parse_footers(self._message +
  53. 'Bug:\n' +
  54. self._position_footer),
  55. { 'Bug': [''],
  56. 'Cr-Commit-Position': [ self._position ] })
  57. def testSkippingBadFooterLines(self):
  58. message = ('Title.\n'
  59. '\n'
  60. 'Last: paragraph starts\n'
  61. 'It-may: contain\n'
  62. 'bad lines, which should be skipped\n'
  63. 'For: example\n'
  64. '(cherry picked from)\n'
  65. 'And-only-valid: footers taken')
  66. self.assertEqual(git_footers.split_footers(message),
  67. (['Title.',
  68. ''],
  69. ['Last: paragraph starts',
  70. 'It-may: contain',
  71. 'bad lines, which should be skipped',
  72. 'For: example',
  73. '(cherry picked from)',
  74. 'And-only-valid: footers taken'],
  75. [('Last', 'paragraph starts'),
  76. ('It-may', 'contain'),
  77. ('For', 'example'),
  78. ('And-only-valid', 'footers taken')]))
  79. self.assertEqual(git_footers.parse_footers(message),
  80. {'Last': ['paragraph starts'],
  81. 'It-May': ['contain'],
  82. 'For': ['example'],
  83. 'And-Only-Valid': ['footers taken']})
  84. def testAvoidingURLs(self):
  85. message = ('Someone accidentally put a URL in the footers.\n'
  86. '\n'
  87. 'Followed: by\n'
  88. 'http://domain.tld\n'
  89. 'Some: footers')
  90. self.assertEqual(git_footers.split_footers(message),
  91. (['Someone accidentally put a URL in the footers.',
  92. ''],
  93. ['Followed: by',
  94. 'http://domain.tld',
  95. 'Some: footers'],
  96. [('Followed', 'by'),
  97. ('Some', 'footers')]))
  98. self.assertEqual(git_footers.parse_footers(message),
  99. {'Followed': ['by'],
  100. 'Some': ['footers']})
  101. def testSplittingLastParagraph(self):
  102. message = ('Title.\n'
  103. '\n'
  104. 'The final paragraph has some normal text first.\n'
  105. 'Followed: by\n'
  106. 'nonsense trailers and\n'
  107. 'Some: footers')
  108. self.assertEqual(git_footers.split_footers(message),
  109. (['Title.',
  110. '',
  111. 'The final paragraph has some normal text first.',
  112. ''],
  113. ['Followed: by',
  114. 'nonsense trailers and',
  115. 'Some: footers'],
  116. [('Followed', 'by'),
  117. ('Some', 'footers')]))
  118. self.assertEqual(git_footers.parse_footers(message),
  119. {'Followed': ['by'],
  120. 'Some': ['footers']})
  121. def testGetFooterChangeId(self):
  122. msg = '\n'.join(['whatever',
  123. '',
  124. 'Change-Id: ignored',
  125. '', # Above is ignored because of this empty line.
  126. 'Change-Id: Ideadbeaf'])
  127. self.assertEqual(['Ideadbeaf'], git_footers.get_footer_change_id(msg))
  128. self.assertEqual([], git_footers.get_footer_change_id(
  129. 'desc\nBUG=not-a-valid-footer\nChange-Id: Ixxx'))
  130. self.assertEqual(['Ixxx'], git_footers.get_footer_change_id(
  131. 'desc\nBUG=not-a-valid-footer\n\nChange-Id: Ixxx'))
  132. def testAddFooterChangeId(self):
  133. with self.assertRaises(AssertionError):
  134. git_footers.add_footer_change_id('Already has\n\nChange-Id: Ixxx', 'Izzz')
  135. self.assertEqual(
  136. git_footers.add_footer_change_id('header-only', 'Ixxx'),
  137. 'header-only\n\nChange-Id: Ixxx')
  138. self.assertEqual(
  139. git_footers.add_footer_change_id('header\n\nsome: footer', 'Ixxx'),
  140. 'header\n\nsome: footer\nChange-Id: Ixxx')
  141. self.assertEqual(
  142. git_footers.add_footer_change_id('header\n\nBUG: yy', 'Ixxx'),
  143. 'header\n\nBUG: yy\nChange-Id: Ixxx')
  144. self.assertEqual(
  145. git_footers.add_footer_change_id('header\n\nBUG: yy\nPos: 1', 'Ixxx'),
  146. 'header\n\nBUG: yy\nChange-Id: Ixxx\nPos: 1')
  147. self.assertEqual(
  148. git_footers.add_footer_change_id('header\n\nBUG: yy\n\nPos: 1', 'Ixxx'),
  149. 'header\n\nBUG: yy\n\nPos: 1\nChange-Id: Ixxx')
  150. # Special case: first line is never a footer, even if it looks line one.
  151. self.assertEqual(
  152. git_footers.add_footer_change_id('header: like footer', 'Ixxx'),
  153. 'header: like footer\n\nChange-Id: Ixxx')
  154. self.assertEqual(
  155. git_footers.add_footer_change_id('Header.\n\nBug: v8\nN=t\nT=z', 'Ix'),
  156. 'Header.\n\nBug: v8\nChange-Id: Ix\nN=t\nT=z')
  157. def testAddFooter(self):
  158. with self.assertRaises(ValueError):
  159. git_footers.add_footer('', 'Invalid Footer', 'Value')
  160. self.assertEqual(
  161. git_footers.add_footer('', 'Key', 'Value'),
  162. '\nKey: Value')
  163. self.assertEqual(
  164. git_footers.add_footer('Header with empty line.\n\n', 'Key', 'Value'),
  165. 'Header with empty line.\n\nKey: Value')
  166. self.assertEqual(
  167. git_footers.add_footer('Top\n\nSome: footer', 'Key', 'value'),
  168. 'Top\n\nSome: footer\nKey: value')
  169. self.assertEqual(
  170. git_footers.add_footer('Top\n\nSome: footer', 'Key', 'value',
  171. after_keys=['Any']),
  172. 'Top\n\nSome: footer\nKey: value')
  173. self.assertEqual(
  174. git_footers.add_footer('Top\n\nSome: footer', 'Key', 'value',
  175. after_keys=['Some']),
  176. 'Top\n\nSome: footer\nKey: value')
  177. self.assertEqual(
  178. git_footers.add_footer('Top\n\nSome: footer\nOther: footer',
  179. 'Key', 'value', after_keys=['Some']),
  180. 'Top\n\nSome: footer\nKey: value\nOther: footer')
  181. self.assertEqual(
  182. git_footers.add_footer('Top\n\nSome: footer\nOther: footer',
  183. 'Key', 'value', before_keys=['Other']),
  184. 'Top\n\nSome: footer\nKey: value\nOther: footer')
  185. self.assertEqual(
  186. git_footers.add_footer(
  187. 'Top\n\nSome: footer\nOther: footer\nFinal: footer',
  188. 'Key', 'value', after_keys=['Some'], before_keys=['Final']),
  189. 'Top\n\nSome: footer\nKey: value\nOther: footer\nFinal: footer')
  190. self.assertEqual(
  191. git_footers.add_footer(
  192. 'Top\n\nSome: footer\nOther: footer\nFinal: footer',
  193. 'Key', 'value', after_keys=['Other'], before_keys=['Some']),
  194. 'Top\n\nSome: footer\nOther: footer\nKey: value\nFinal: footer')
  195. def testRemoveFooter(self):
  196. self.assertEqual(
  197. git_footers.remove_footer('message', 'Key'),
  198. 'message')
  199. self.assertEqual(
  200. git_footers.remove_footer('message\n\nSome: footer', 'Key'),
  201. 'message\n\nSome: footer')
  202. self.assertEqual(
  203. git_footers.remove_footer('message\n\nSome: footer\nKey: value', 'Key'),
  204. 'message\n\nSome: footer')
  205. self.assertEqual(
  206. git_footers.remove_footer(
  207. 'message\n\nKey: value\nSome: footer\nKey: value', 'Key'),
  208. 'message\n\nSome: footer')
  209. @mock.patch('sys.stdout', StringIO())
  210. @mock.patch(
  211. 'sys.stdin',
  212. StringIO('line\r\notherline\r\n\r\n\r\nFoo: baz\r\nStill: footer'))
  213. def testReadStdin(self):
  214. self.assertEqual(git_footers.main([]), 0)
  215. self.assertEqual(sys.stdout.getvalue(), 'Still: footer\nFoo: baz\n')
  216. @mock.patch(
  217. 'sys.stdin',
  218. StringIO('line\r\nany spaces\r\n\r\n\r\nFoo: 1\nBar: 2\nFoo: 3'))
  219. def testToJson(self):
  220. with gclient_utils.temporary_file() as tmp:
  221. self.assertEqual(git_footers.main(['--json', tmp]), 0)
  222. with open(tmp) as f:
  223. js = json.load(f)
  224. self.assertEqual(js, {'Foo': ['3', '1'], 'Bar': ['2']})
  225. if __name__ == '__main__':
  226. unittest.main()