ZeroInstallFeed._get_impl always creates a new Implementation
[zeroinstall/solver.git] / tests / testmodel.py
blobf87ebf1a7d4d0a560f2252ec797698ca23a38a27
1 #!/usr/bin/env python2.5
2 # -*- coding: utf-8 -*-
3 from basetest import BaseTest, empty_feed
4 import sys
5 from xml.dom import minidom
6 import unittest
7 from StringIO import StringIO
9 sys.path.insert(0, '..')
10 from zeroinstall.injector import model, qdom
12 class TestModel(BaseTest):
13 def testLevels(self):
14 assert model.network_offline in model.network_levels
15 assert model.network_minimal in model.network_levels
16 assert model.network_full in model.network_levels
18 def testStabilities(self):
19 assert 'insecure' in model.stability_levels
20 assert 'buggy' in model.stability_levels
21 assert 'developer' in model.stability_levels
22 assert 'testing' in model.stability_levels
23 assert 'stable' in model.stability_levels
24 assert 'preferred' in model.stability_levels
25 str(model.insecure)
27 def testEscape(self):
28 self.assertEquals("", model.escape(""))
29 self.assertEquals("hello", model.escape("hello"))
30 self.assertEquals("%20", model.escape(" "))
32 self.assertEquals("file%3a%2f%2ffoo%7ebar",
33 model.escape("file://foo~bar"))
34 self.assertEquals("file%3a%2f%2ffoo%25bar",
35 model.escape("file://foo%bar"))
37 self.assertEquals("file:##foo%7ebar",
38 model._pretty_escape("file://foo~bar"))
39 self.assertEquals("file:##foo%25bar",
40 model._pretty_escape("file://foo%bar"))
42 def testUnescape(self):
43 self.assertEquals("", model.unescape(""))
44 self.assertEquals("hello", model.unescape("hello"))
45 self.assertEquals(" ", model.unescape("%20"))
47 self.assertEquals("file://foo~bar",
48 model.unescape("file%3a%2f%2ffoo%7ebar"))
49 self.assertEquals("file://foo%bar",
50 model.unescape("file%3a%2f%2ffoo%25bar"))
52 self.assertEquals("file://foo",
53 model.unescape("file:##foo"))
54 self.assertEquals("file://foo~bar",
55 model.unescape("file:##foo%7ebar"))
56 self.assertEquals("file://foo%bar",
57 model.unescape("file:##foo%25bar"))
59 def testEscaping(self):
60 def check(str):
61 self.assertEquals(str, model.unescape(model.escape(str)))
62 self.assertEquals(str, model.unescape(model._pretty_escape(str)))
64 check(u'http://example.com')
65 check(u'http://example%46com')
66 check(u'http:##example#com')
67 check(u'http://example.com/foo/bar.xml')
68 check(u'%20%21~&!"£ :@;,./{}$%^&()')
70 def testBadInterface(self):
71 try:
72 model.Interface('foo')
73 assert 0
74 except model.SafeException:
75 pass
77 def testInterface(self):
78 i = model.Interface('http://foo')
79 self.assertEquals('(foo)', i.get_name())
80 feed = model.ZeroInstallFeed(empty_feed, local_path = '/foo')
81 i._main_feed = feed
82 self.assertEquals('Empty', i.get_name())
83 repr(i)
85 def testMetadata(self):
86 i = model.Interface('http://foo')
87 i._main_feed = model.ZeroInstallFeed(empty_feed, local_path = '/foo')
88 e = qdom.parse(StringIO('<ns:b xmlns:ns="a" foo="bar"/>'))
89 i._main_feed.metadata = [e]
90 assert i.get_metadata('a', 'b') == [e]
91 assert i.get_metadata('b', 'b') == []
92 assert i.get_metadata('a', 'a') == []
93 assert e.getAttribute('foo') == 'bar'
95 def testStabPolicy(self):
96 i = model.Interface('http://foo')
97 self.assertEquals(None, i.stability_policy)
98 i.set_stability_policy(model.buggy)
99 self.assertEquals(model.buggy, i.stability_policy)
101 def testGetImpl(self):
102 i = model.Interface('http://foo')
103 feed = model.ZeroInstallFeed(empty_feed, local_path = '/foo')
104 a = feed._get_impl('foo')
105 b = feed._get_impl('bar')
106 try:
107 c = feed._get_impl('foo')
108 assert 0
109 except:
110 pass
111 assert a and b
112 assert a is not b
113 assert isinstance(a, model.ZeroInstallImplementation)
115 def testImpl(self):
116 i = model.Interface('http://foo')
117 a = model.ZeroInstallImplementation(i, 'foo')
118 assert a.id == 'foo'
119 assert a.size == a.version == a.user_stability == None
120 assert a.arch == a.upstream_stability == None
121 assert a.dependencies == {}
122 assert a.download_sources == []
123 assert a.get_stability() is model.testing
124 a.upstream_stability = model.stable
125 assert a.get_stability() is model.stable
126 a.user_stability = model.buggy
127 assert a.get_stability() is model.buggy
128 a.version = model.parse_version('1.2.3')
129 self.assertEquals('1.2.3', a.get_version())
130 a.version = model.parse_version('1.2.3-rc2-post')
131 self.assertEquals('1.2.3-rc2-post', a.get_version())
132 assert str(a) == 'foo'
134 b = model.ZeroInstallImplementation(i, 'foo')
135 b.version = [1,2,1]
136 assert b > a
138 def testDownloadSource(self):
139 f = model.ZeroInstallFeed(empty_feed, local_path = '/foo')
140 a = model.ZeroInstallImplementation(f, 'foo')
141 a.add_download_source('ftp://foo', 1024, None)
142 a.add_download_source('ftp://foo.tgz', 1025, 'foo')
143 assert a.download_sources[0].url == 'ftp://foo'
144 assert a.download_sources[0].size == 1024
145 assert a.download_sources[0].extract == None
146 assert a.feed is f
148 def testEnvBind(self):
149 a = model.EnvironmentBinding('PYTHONPATH', 'path')
150 assert a.name == 'PYTHONPATH'
151 assert a.insert == 'path'
152 str(a)
154 def testEnvModes(self):
155 prepend = model.EnvironmentBinding('PYTHONPATH', 'lib', None, model.EnvironmentBinding.PREPEND)
156 assert prepend.name == 'PYTHONPATH'
157 assert prepend.insert == 'lib'
158 assert prepend.mode is model.EnvironmentBinding.PREPEND
160 self.assertEquals('/impl/lib:/usr/lib', prepend.get_value('/impl', '/usr/lib'))
161 self.assertEquals('/impl/lib', prepend.get_value('/impl', None))
163 append = model.EnvironmentBinding('PYTHONPATH', 'lib', '/opt/lib', model.EnvironmentBinding.APPEND)
164 assert append.name == 'PYTHONPATH'
165 assert append.insert == 'lib'
166 assert append.mode is model.EnvironmentBinding.APPEND
168 self.assertEquals('/usr/lib:/impl/lib', append.get_value('/impl', '/usr/lib'))
169 self.assertEquals('/opt/lib:/impl/lib', append.get_value('/impl', None))
171 append = model.EnvironmentBinding('PYTHONPATH', 'lib', None, model.EnvironmentBinding.REPLACE)
172 assert append.name == 'PYTHONPATH'
173 assert append.insert == 'lib'
174 assert append.mode is model.EnvironmentBinding.REPLACE
176 self.assertEquals('/impl/lib', append.get_value('/impl', '/usr/lib'))
177 self.assertEquals('/impl/lib', append.get_value('/impl', None))
179 assert model.EnvironmentBinding('PYTHONPATH', 'lib').mode == model.EnvironmentBinding.PREPEND
181 def testOverlay(self):
182 for xml, expected in [('<overlay/>', '<overlay . on />'),
183 ('<overlay src="usr"/>', '<overlay usr on />'),
184 ('<overlay src="package" mount-point="/usr/games"/>', '<overlay package on /usr/games>')]:
185 e = qdom.parse(StringIO(xml))
186 ol = model.process_binding(e)
187 self.assertEquals(expected, str(ol))
189 doc = minidom.parseString('<doc/>')
190 new_xml = str(ol._toxml(doc).toxml())
191 new_e = qdom.parse(StringIO(new_xml))
192 new_ol = model.process_binding(new_e)
193 self.assertEquals(expected, str(new_ol))
195 def testDep(self):
196 b = model.InterfaceDependency('http://foo')
197 assert not b.restrictions
198 assert not b.bindings
199 str(b)
201 def testFeed(self):
202 f = model.Feed('http://feed', arch = None, user_override = False)
203 assert f.uri == 'http://feed'
204 assert f.os == None
205 assert f.machine == None
206 assert f.arch == None
207 assert f.user_override == False
209 f = model.Feed('http://feed', arch = 'Linux-*', user_override = True)
210 assert f.uri == 'http://feed'
211 assert f.os == 'Linux'
212 assert f.machine == None
213 assert f.arch == 'Linux-*'
214 assert f.user_override == True
216 f = model.Feed('http://feed', arch = '*-i386', user_override = True)
217 assert f.uri == 'http://feed'
218 assert f.os == None
219 assert f.machine == 'i386'
220 assert f.arch == '*-i386'
221 assert f.user_override == True
222 assert str(f).startswith('<Feed from')
224 try:
225 f = model.Feed('http://feed', arch = 'i386', user_override = True)
226 assert False
227 except model.SafeException, ex:
228 assert 'Malformed arch' in str(ex)
230 def testCanonical(self):
231 try:
232 model.canonical_iface_uri('http://foo')
233 assert False
234 except model.SafeException, ex:
235 assert 'Missing /' in str(ex)
237 self.assertEquals('http://foo/',
238 model.canonical_iface_uri('http://foo/'))
239 try:
240 model.canonical_iface_uri('bad-name')
241 assert False
242 except model.SafeException, ex:
243 assert 'Bad interface name' in str(ex)
245 def testVersions(self):
246 def pv(v):
247 parsed = model.parse_version(v)
248 assert model.format_version(parsed) == v
249 return parsed
251 assert pv('1.0') > pv('0.9')
252 assert pv('1.0') > pv('1')
253 assert pv('1.0') == pv('1.0')
254 assert pv('0.9.9') < pv('1.0')
255 assert pv('10') > pv('2')
257 def invalid(v):
258 try:
259 pv(v)
260 assert False
261 except model.SafeException, ex:
262 pass
263 invalid('.')
264 invalid('hello')
265 invalid('2./1')
266 invalid('.1')
267 invalid('')
269 # Check parsing
270 assert pv('1') == [[1], 0]
271 assert pv('1.0') == [[1,0], 0]
272 assert pv('1.0-pre5') == [[1,0], -2, [5], 0]
273 assert pv('1.0-rc5') == [[1,0], -1, [5], 0]
274 assert pv('1.0-5') == [[1,0], 0, [5], 0]
275 assert pv('1.0-post5') == [[1,0], 1, [5], 0]
276 assert pv('1.0-post') == [[1,0], 1]
277 assert pv('1-rc2.0-pre2-post') == [[1], -1, [2,0], -2, [2], 1]
278 assert pv('1-rc2.0-pre-post') == [[1], -1, [2,0], -2, [], 1]
280 assert pv('1.0-0') > pv('1.0')
281 assert pv('1.0-1') > pv('1.0-0')
282 assert pv('1.0-0') < pv('1.0-1')
284 assert pv('1.0-pre99') > pv('1.0-pre1')
285 assert pv('1.0-pre99') < pv('1.0-rc1')
286 assert pv('1.0-rc1') < pv('1.0')
287 assert pv('1.0') < pv('1.0-0')
288 assert pv('1.0-0') < pv('1.0-post')
289 assert pv('2.1.9-pre-1') > pv('2.1.9-pre')
291 assert pv('2-post999') < pv('3-pre1')
293 suite = unittest.makeSuite(TestModel)
294 if __name__ == '__main__':
295 sys.argv.append('-v')
296 unittest.main()