You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
8.9KB

  1. # test_utils.py
  2. # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
  3. #
  4. # This module is part of GitPython and is released under
  5. # the BSD License: http://www.opensource.org/licenses/bsd-license.php
  6. import tempfile
  7. import time
  8. from unittest import skipIf
  9. from datetime import datetime
  10. import ddt
  11. from git.cmd import dashify
  12. from git.compat import string_types, is_win
  13. from git.objects.util import (
  14. altz_to_utctz_str,
  15. utctz_to_altz,
  16. verify_utctz,
  17. parse_date,
  18. tzoffset,
  19. from_timestamp)
  20. from git.test.lib import (
  21. TestBase,
  22. assert_equal
  23. )
  24. from git.util import (
  25. LockFile,
  26. BlockingLockFile,
  27. get_user_id,
  28. Actor,
  29. IterableList,
  30. cygpath,
  31. decygpath
  32. )
  33. _norm_cygpath_pairs = (
  34. (r'foo\bar', 'foo/bar'),
  35. (r'foo/bar', 'foo/bar'),
  36. (r'C:\Users', '/cygdrive/c/Users'),
  37. (r'C:\d/e', '/cygdrive/c/d/e'),
  38. ('C:\\', '/cygdrive/c/'),
  39. (r'\\server\C$\Users', '//server/C$/Users'),
  40. (r'\\server\C$', '//server/C$'),
  41. ('\\\\server\\c$\\', '//server/c$/'),
  42. (r'\\server\BAR/', '//server/BAR/'),
  43. (r'D:/Apps', '/cygdrive/d/Apps'),
  44. (r'D:/Apps\fOO', '/cygdrive/d/Apps/fOO'),
  45. (r'D:\Apps/123', '/cygdrive/d/Apps/123'),
  46. )
  47. _unc_cygpath_pairs = (
  48. (r'\\?\a:\com', '/cygdrive/a/com'),
  49. (r'\\?\a:/com', '/cygdrive/a/com'),
  50. (r'\\?\UNC\server\D$\Apps', '//server/D$/Apps'),
  51. )
  52. class TestIterableMember(object):
  53. """A member of an iterable list"""
  54. __slots__ = "name"
  55. def __init__(self, name):
  56. self.name = name
  57. def __repr__(self):
  58. return "TestIterableMember(%r)" % self.name
  59. @ddt.ddt
  60. class TestUtils(TestBase):
  61. def setup(self):
  62. self.testdict = {
  63. "string": "42",
  64. "int": 42,
  65. "array": [42],
  66. }
  67. @skipIf(not is_win, "Paths specifically for Windows.")
  68. @ddt.idata(_norm_cygpath_pairs + _unc_cygpath_pairs)
  69. def test_cygpath_ok(self, case):
  70. wpath, cpath = case
  71. cwpath = cygpath(wpath)
  72. self.assertEqual(cwpath, cpath, wpath)
  73. @skipIf(not is_win, "Paths specifically for Windows.")
  74. @ddt.data(
  75. (r'./bar', 'bar'),
  76. (r'.\bar', 'bar'),
  77. (r'../bar', '../bar'),
  78. (r'..\bar', '../bar'),
  79. (r'../bar/.\foo/../chu', '../bar/chu'),
  80. )
  81. def test_cygpath_norm_ok(self, case):
  82. wpath, cpath = case
  83. cwpath = cygpath(wpath)
  84. self.assertEqual(cwpath, cpath or wpath, wpath)
  85. @skipIf(not is_win, "Paths specifically for Windows.")
  86. @ddt.data(
  87. r'C:',
  88. r'C:Relative',
  89. r'D:Apps\123',
  90. r'D:Apps/123',
  91. r'\\?\a:rel',
  92. r'\\share\a:rel',
  93. )
  94. def test_cygpath_invalids(self, wpath):
  95. cwpath = cygpath(wpath)
  96. self.assertEqual(cwpath, wpath.replace('\\', '/'), wpath)
  97. @skipIf(not is_win, "Paths specifically for Windows.")
  98. @ddt.idata(_norm_cygpath_pairs)
  99. def test_decygpath(self, case):
  100. wpath, cpath = case
  101. wcpath = decygpath(cpath)
  102. self.assertEqual(wcpath, wpath.replace('/', '\\'), cpath)
  103. def test_it_should_dashify(self):
  104. assert_equal('this-is-my-argument', dashify('this_is_my_argument'))
  105. assert_equal('foo', dashify('foo'))
  106. def test_lock_file(self):
  107. my_file = tempfile.mktemp()
  108. lock_file = LockFile(my_file)
  109. assert not lock_file._has_lock()
  110. # release lock we don't have - fine
  111. lock_file._release_lock()
  112. # get lock
  113. lock_file._obtain_lock_or_raise()
  114. assert lock_file._has_lock()
  115. # concurrent access
  116. other_lock_file = LockFile(my_file)
  117. assert not other_lock_file._has_lock()
  118. self.failUnlessRaises(IOError, other_lock_file._obtain_lock_or_raise)
  119. lock_file._release_lock()
  120. assert not lock_file._has_lock()
  121. other_lock_file._obtain_lock_or_raise()
  122. self.failUnlessRaises(IOError, lock_file._obtain_lock_or_raise)
  123. # auto-release on destruction
  124. del(other_lock_file)
  125. lock_file._obtain_lock_or_raise()
  126. lock_file._release_lock()
  127. def test_blocking_lock_file(self):
  128. my_file = tempfile.mktemp()
  129. lock_file = BlockingLockFile(my_file)
  130. lock_file._obtain_lock()
  131. # next one waits for the lock
  132. start = time.time()
  133. wait_time = 0.1
  134. wait_lock = BlockingLockFile(my_file, 0.05, wait_time)
  135. self.failUnlessRaises(IOError, wait_lock._obtain_lock)
  136. elapsed = time.time() - start
  137. extra_time = 0.02
  138. if is_win:
  139. # for Appveyor
  140. extra_time *= 6 # NOTE: Indeterministic failures here...
  141. self.assertLess(elapsed, wait_time + extra_time)
  142. def test_user_id(self):
  143. self.assertIn('@', get_user_id())
  144. def test_parse_date(self):
  145. # test all supported formats
  146. def assert_rval(rval, veri_time, offset=0):
  147. self.assertEqual(len(rval), 2)
  148. self.assertIsInstance(rval[0], int)
  149. self.assertIsInstance(rval[1], int)
  150. self.assertEqual(rval[0], veri_time)
  151. self.assertEqual(rval[1], offset)
  152. # now that we are here, test our conversion functions as well
  153. utctz = altz_to_utctz_str(offset)
  154. self.assertIsInstance(utctz, string_types)
  155. self.assertEqual(utctz_to_altz(verify_utctz(utctz)), offset)
  156. # END assert rval utility
  157. rfc = ("Thu, 07 Apr 2005 22:13:11 +0000", 0)
  158. iso = ("2005-04-07T22:13:11 -0200", 7200)
  159. iso2 = ("2005-04-07 22:13:11 +0400", -14400)
  160. iso3 = ("2005.04.07 22:13:11 -0000", 0)
  161. alt = ("04/07/2005 22:13:11", 0)
  162. alt2 = ("07.04.2005 22:13:11", 0)
  163. veri_time_utc = 1112911991 # the time this represents, in time since epoch, UTC
  164. for date, offset in (rfc, iso, iso2, iso3, alt, alt2):
  165. assert_rval(parse_date(date), veri_time_utc, offset)
  166. # END for each date type
  167. # and failure
  168. self.failUnlessRaises(ValueError, parse_date, 'invalid format')
  169. self.failUnlessRaises(ValueError, parse_date, '123456789 -02000')
  170. self.failUnlessRaises(ValueError, parse_date, ' 123456789 -0200')
  171. def test_actor(self):
  172. for cr in (None, self.rorepo.config_reader()):
  173. self.assertIsInstance(Actor.committer(cr), Actor)
  174. self.assertIsInstance(Actor.author(cr), Actor)
  175. # END assure config reader is handled
  176. def test_actor_from_string(self):
  177. self.assertEqual(Actor._from_string("name"), Actor("name", None))
  178. self.assertEqual(Actor._from_string("name <>"), Actor("name", ""))
  179. self.assertEqual(Actor._from_string("name last another <some-very-long-email@example.com>"),
  180. Actor("name last another", "some-very-long-email@example.com"))
  181. @ddt.data(('name', ''), ('name', 'prefix_'))
  182. def test_iterable_list(self, case):
  183. name, prefix = case
  184. ilist = IterableList(name, prefix)
  185. name1 = "one"
  186. name2 = "two"
  187. m1 = TestIterableMember(prefix + name1)
  188. m2 = TestIterableMember(prefix + name2)
  189. ilist.extend((m1, m2))
  190. self.assertEqual(len(ilist), 2)
  191. # contains works with name and identity
  192. self.assertIn(name1, ilist)
  193. self.assertIn(name2, ilist)
  194. self.assertIn(m2, ilist)
  195. self.assertIn(m2, ilist)
  196. self.assertNotIn('invalid', ilist)
  197. # with string index
  198. self.assertIs(ilist[name1], m1)
  199. self.assertIs(ilist[name2], m2)
  200. # with int index
  201. self.assertIs(ilist[0], m1)
  202. self.assertIs(ilist[1], m2)
  203. # with getattr
  204. self.assertIs(ilist.one, m1)
  205. self.assertIs(ilist.two, m2)
  206. # test exceptions
  207. self.failUnlessRaises(AttributeError, getattr, ilist, 'something')
  208. self.failUnlessRaises(IndexError, ilist.__getitem__, 'something')
  209. # delete by name and index
  210. self.failUnlessRaises(IndexError, ilist.__delitem__, 'something')
  211. del(ilist[name2])
  212. self.assertEqual(len(ilist), 1)
  213. self.assertNotIn(name2, ilist)
  214. self.assertIn(name1, ilist)
  215. del(ilist[0])
  216. self.assertNotIn(name1, ilist)
  217. self.assertEqual(len(ilist), 0)
  218. self.failUnlessRaises(IndexError, ilist.__delitem__, 0)
  219. self.failUnlessRaises(IndexError, ilist.__delitem__, 'something')
  220. def test_from_timestamp(self):
  221. # Correct offset: UTC+2, should return datetime + tzoffset(+2)
  222. altz = utctz_to_altz('+0200')
  223. self.assertEqual(datetime.fromtimestamp(1522827734, tzoffset(altz)), from_timestamp(1522827734, altz))
  224. # Wrong offset: UTC+58, should return datetime + tzoffset(UTC)
  225. altz = utctz_to_altz('+5800')
  226. self.assertEqual(datetime.fromtimestamp(1522827734, tzoffset(0)), from_timestamp(1522827734, altz))
  227. # Wrong offset: UTC-9000, should return datetime + tzoffset(UTC)
  228. altz = utctz_to_altz('-9000')
  229. self.assertEqual(datetime.fromtimestamp(1522827734, tzoffset(0)), from_timestamp(1522827734, altz))