]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/test_version.py
296db0624c2f34f9adc666c716bad66747f68088
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_version.py
1
2 from twisted.trial import unittest
3
4 from allmydata import check_requirement, cross_check, PackagingError
5 from allmydata.util.verlib import NormalizedVersion as V, \
6                                   IrrationalVersionError, \
7                                   suggest_normalized_version as suggest
8
9
10 class CheckRequirement(unittest.TestCase):
11     def test_check_requirement(self):
12         check_requirement("setuptools >= 0.6c6", {"setuptools": ("0.6", "", None)})
13         check_requirement("setuptools >= 0.6c6", {"setuptools": ("0.6", "", "distribute")})
14         check_requirement("pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.1.0", "", None)})
15         check_requirement("pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.4.0", "", None)})
16         check_requirement("zope.interface <= 3.6.2, >= 3.6.6", {"zope.interface": ("3.6.1", "", None)})
17         check_requirement("zope.interface <= 3.6.2, >= 3.6.6", {"zope.interface": ("3.6.6", "", None)})
18
19         check_requirement("zope.interface", {"zope.interface": ("unknown", "", None)})
20         check_requirement("mock", {"mock": ("0.6.0", "", None)})
21         check_requirement("foo >= 1.0", {"foo": ("1.0", "", None), "bar": ("2.0", "", None)})
22
23         check_requirement("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.7.0", "", None)})
24
25         try:
26             check_requirement("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.6.1+", "", None)})
27             # succeeding is ok
28         except PackagingError, e:
29             self.failUnlessIn("could not parse", str(e))
30
31         self.failUnlessRaises(PackagingError, check_requirement,
32                               "foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.5.1", "", None)})
33         self.failUnlessRaises(PackagingError, check_requirement,
34                               "pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.2.0", "", None)})
35         self.failUnlessRaises(PackagingError, check_requirement,
36                               "zope.interface <= 3.6.2, >= 3.6.6", {"zope.interface": ("3.6.4", "", None)})
37         self.failUnlessRaises(PackagingError, check_requirement,
38                               "foo >= 1.0", {})
39         self.failUnlessRaises(PackagingError, check_requirement,
40                               "foo >= 1.0", {"foo": ("irrational", "", None)})
41
42         self.failUnlessRaises(ImportError, check_requirement,
43                               "foo >= 1.0", {"foo": (None, None, "foomodule")})
44
45     def test_cross_check_ticket_1355(self):
46         # The bug in #1355 is triggered when a version string from either pkg_resources or import
47         # is not parseable at all by normalized_version.
48
49         res = cross_check({"foo": ("unparseable", "")}, [("foo", ("1.0", "", None))])
50         self.failUnlessEqual(len(res), 1)
51         self.failUnlessIn("by pkg_resources could not be parsed", res[0])
52
53         res = cross_check({"foo": ("1.0", "")}, [("foo", ("unparseable", "", None))])
54         self.failUnlessEqual(len(res), 1)
55         self.failUnlessIn(") could not be parsed", res[0])
56
57     def test_cross_check(self):
58         res = cross_check({}, [])
59         self.failUnlessEqual(res, [])
60
61         res = cross_check({}, [("allmydata-tahoe", ("1.0", "", "blah"))])
62         self.failUnlessEqual(res, [])
63
64         res = cross_check({"foo": ("unparseable", "")}, [])
65         self.failUnlessEqual(len(res), 1)
66         self.failUnlessIn("not found by import", res[0])
67
68         res = cross_check({"argparse": ("unparseable", "")}, [])
69         self.failUnlessEqual(len(res), 0)
70
71         res = cross_check({}, [("foo", ("unparseable", "", None))])
72         self.failUnlessEqual(len(res), 1)
73         self.failUnlessIn("not found by pkg_resources", res[0])
74
75         res = cross_check({"distribute": ("1.0", "/somewhere")}, [("setuptools", ("2.0", "/somewhere", "distribute"))])
76         self.failUnlessEqual(len(res), 0)
77
78         res = cross_check({"distribute": ("1.0", "/somewhere")}, [("setuptools", ("2.0", "/somewhere", None))])
79         self.failUnlessEqual(len(res), 1)
80         self.failUnlessIn("location mismatch", res[0])
81
82         res = cross_check({"distribute": ("1.0", "/somewhere")}, [("setuptools", ("2.0", "/somewhere_different", None))])
83         self.failUnlessEqual(len(res), 1)
84         self.failUnlessIn("location mismatch", res[0])
85
86         res = cross_check({"zope.interface": ("1.0", "")}, [("zope.interface", ("unknown", "", None))])
87         self.failUnlessEqual(len(res), 0)
88
89         res = cross_check({"foo": ("1.0", "")}, [("foo", ("unknown", "", None))])
90         self.failUnlessEqual(len(res), 1)
91         self.failUnlessIn("could not find a version number", res[0])
92
93         # When pkg_resources and import both find a package, there is only a warning if both
94         # the version and the path fail to match.
95
96         res = cross_check({"foo": ("1.0", "/somewhere")}, [("foo", ("2.0", "/somewhere", None))])
97         self.failUnlessEqual(len(res), 0)
98
99         res = cross_check({"foo": ("1.0", "/somewhere")}, [("foo", ("1.0", "/somewhere_different", None))])
100         self.failUnlessEqual(len(res), 0)
101
102         res = cross_check({"foo": ("1.0-r123", "/somewhere")}, [("foo", ("1.0.post123", "/somewhere_different", None))])
103         self.failUnlessEqual(len(res), 0)
104
105         res = cross_check({"foo": ("1.0", "/somewhere")}, [("foo", ("2.0", "/somewhere_different", None))])
106         self.failUnlessEqual(len(res), 1)
107         self.failUnlessIn("but version '2.0'", res[0])
108
109
110 # based on https://bitbucket.org/tarek/distutilsversion/src/17df9a7d96ef/test_verlib.py
111
112 class VersionTestCase(unittest.TestCase):
113     versions = ((V('1.0'), '1.0'),
114                 (V('1.1'), '1.1'),
115                 (V('1.2.3'), '1.2.3'),
116                 (V('1.2'), '1.2'),
117                 (V('1.2.3a4'), '1.2.3a4'),
118                 (V('1.2c4'), '1.2c4'),
119                 (V('1.2.3.4'), '1.2.3.4'),
120                 (V('1.2.3.4.0b3'), '1.2.3.4b3'),
121                 (V('1.2.0.0.0'), '1.2'),
122                 (V('1.0.dev345'), '1.0.dev345'),
123                 (V('1.0.post456.dev623'), '1.0.post456.dev623'))
124
125     def test_basic_versions(self):
126         for v, s in self.versions:
127             self.failUnlessEqual(str(v), s)
128
129     def test_from_parts(self):
130         for v, s in self.versions:
131             parts = v.parts
132             v2 = V.from_parts(*parts)
133             self.failUnlessEqual(v, v2)
134             self.failUnlessEqual(str(v), str(v2))
135
136     def test_irrational_versions(self):
137         irrational = ('1', '1.2a', '1.2.3b', '1.02', '1.2a03',
138                       '1.2a3.04', '1.2.dev.2', '1.2dev', '1.2.dev',
139                       '1.2.dev2.post2', '1.2.post2.dev3.post4')
140
141         for s in irrational:
142             self.failUnlessRaises(IrrationalVersionError, V, s)
143
144     def test_comparison(self):
145         self.failUnlessRaises(TypeError, lambda: V('1.2.0') == '1.2')
146
147         self.failUnlessEqual(V('1.2.0'), V('1.2'))
148         self.failIfEqual(V('1.2.0'), V('1.2.3'))
149         self.failUnless(V('1.2.0') < V('1.2.3'))
150         self.failUnless(V('1.0') > V('1.0b2'))
151         self.failUnless(V('1.0') > V('1.0c2') > V('1.0c1') > V('1.0b2') > V('1.0b1')
152                         > V('1.0a2') > V('1.0a1'))
153         self.failUnless(V('1.0.0') > V('1.0.0c2') > V('1.0.0c1') > V('1.0.0b2') > V('1.0.0b1')
154                         > V('1.0.0a2') > V('1.0.0a1'))
155
156         self.failUnless(V('1.0') < V('1.0.post456.dev623'))
157         self.failUnless(V('1.0.post456.dev623') < V('1.0.post456')  < V('1.0.post1234'))
158
159         self.failUnless(V('1.0a1')
160                         < V('1.0a2.dev456')
161                         < V('1.0a2')
162                         < V('1.0a2.1.dev456')  # e.g. need to do a quick post release on 1.0a2
163                         < V('1.0a2.1')
164                         < V('1.0b1.dev456')
165                         < V('1.0b2')
166                         < V('1.0c1')
167                         < V('1.0c2.dev456')
168                         < V('1.0c2')
169                         < V('1.0.dev7')
170                         < V('1.0.dev18')
171                         < V('1.0.dev456')
172                         < V('1.0.dev1234')
173                         < V('1.0')
174                         < V('1.0.post456.dev623')  # development version of a post release
175                         < V('1.0.post456'))
176
177     def test_suggest_normalized_version(self):
178         self.failUnlessEqual(suggest('1.0'), '1.0')
179         self.failUnlessEqual(suggest('1.0-alpha1'), '1.0a1')
180         self.failUnlessEqual(suggest('1.0c2'), '1.0c2')
181         self.failUnlessEqual(suggest('walla walla washington'), None)
182         self.failUnlessEqual(suggest('2.4c1'), '2.4c1')
183
184         # from setuptools
185         self.failUnlessEqual(suggest('0.4a1.r10'), '0.4a1.post10')
186         self.failUnlessEqual(suggest('0.7a1dev-r66608'), '0.7a1.dev66608')
187         self.failUnlessEqual(suggest('0.6a9.dev-r41475'), '0.6a9.dev41475')
188         self.failUnlessEqual(suggest('2.4preview1'), '2.4c1')
189         self.failUnlessEqual(suggest('2.4pre1') , '2.4c1')
190         self.failUnlessEqual(suggest('2.1-rc2'), '2.1c2')
191
192         # from pypi
193         self.failUnlessEqual(suggest('0.1dev'), '0.1.dev0')
194         self.failUnlessEqual(suggest('0.1.dev'), '0.1.dev0')
195
196         # we want to be able to parse Twisted
197         # development versions are like post releases in Twisted
198         self.failUnlessEqual(suggest('9.0.0+r2363'), '9.0.0.post2363')
199
200         # pre-releases are using markers like "pre1"
201         self.failUnlessEqual(suggest('9.0.0pre1'), '9.0.0c1')
202
203         # we want to be able to parse Tcl-TK
204         # they use "p1" "p2" for post releases
205         self.failUnlessEqual(suggest('1.4p1'), '1.4.post1')
206
207         # from darcsver
208         self.failUnlessEqual(suggest('1.8.1-r4956'), '1.8.1.post4956')
209
210         # zetuptoolz
211         self.failUnlessEqual(suggest('0.6c16dev3'), '0.6c16.dev3')