2 # -*- coding: utf-8 -*-
3 from __future__
import unicode_literals
5 from basetest
import BaseTest
, empty_feed
7 from xml
.dom
import minidom
11 sys
.path
.insert(0, '..')
12 from zeroinstall
.injector
import model
, qdom
, namespaces
14 mydir
= os
.path
.dirname(os
.path
.abspath(__file__
))
16 class TestModel(BaseTest
):
18 assert model
.network_offline
in model
.network_levels
19 assert model
.network_minimal
in model
.network_levels
20 assert model
.network_full
in model
.network_levels
22 def testStabilities(self
):
23 assert 'insecure' in model
.stability_levels
24 assert 'buggy' in model
.stability_levels
25 assert 'developer' in model
.stability_levels
26 assert 'testing' in model
.stability_levels
27 assert 'stable' in model
.stability_levels
28 assert 'preferred' in model
.stability_levels
32 self
.assertEqual("", model
.escape(""))
33 self
.assertEqual("hello", model
.escape("hello"))
34 self
.assertEqual("%20", model
.escape(" "))
36 self
.assertEqual("file%3a%2f%2ffoo%7ebar",
37 model
.escape("file://foo~bar"))
38 self
.assertEqual("file%3a%2f%2ffoo%25bar",
39 model
.escape("file://foo%bar"))
41 self
.assertEqual("file:##foo%7ebar",
42 model
._pretty
_escape
("file://foo~bar"))
43 self
.assertEqual("file:##foo%25bar",
44 model
._pretty
_escape
("file://foo%bar"))
46 def testUnescape(self
):
47 self
.assertEqual("", model
.unescape(""))
48 self
.assertEqual("hello", model
.unescape("hello"))
49 self
.assertEqual(" ", model
.unescape("%20"))
51 self
.assertEqual("file://foo~bar",
52 model
.unescape("file%3a%2f%2ffoo%7ebar"))
53 self
.assertEqual("file://foo%bar",
54 model
.unescape("file%3a%2f%2ffoo%25bar"))
56 self
.assertEqual("file://foo",
57 model
.unescape("file:##foo"))
58 self
.assertEqual("file://foo~bar",
59 model
.unescape("file:##foo%7ebar"))
60 self
.assertEqual("file://foo%bar",
61 model
.unescape("file:##foo%25bar"))
63 def testEscaping(self
):
65 self
.assertEqual(str, model
.unescape(model
.escape(str)))
66 self
.assertEqual(str, model
.unescape(model
._pretty
_escape
(str)))
68 check('http://example.com')
69 check('http://example%46com')
70 check('http:##example#com')
71 check('http://example.com/foo/bar.xml')
72 check('%20%21~&!"£ :@;,./{}$%^&()')
74 def testBadInterface(self
):
76 model
.Interface('foo')
78 except model
.SafeException
:
81 def testInterface(self
):
82 i
= model
.Interface('http://foo')
83 self
.assertEqual('(foo)', i
.get_name())
84 feed
= model
.ZeroInstallFeed(empty_feed
, local_path
= '/foo')
85 self
.assertEqual('Empty', feed
.get_name())
88 def testMetadata(self
):
89 main_feed
= model
.ZeroInstallFeed(empty_feed
, local_path
= '/foo')
90 assert main_feed
.local_path
== "/foo"
91 e
= qdom
.parse(BytesIO(b
'<ns:b xmlns:ns="a" foo="bar"/>'))
92 main_feed
.metadata
= [e
]
93 assert main_feed
.get_metadata('a', 'b') == [e
]
94 assert main_feed
.get_metadata('b', 'b') == []
95 assert main_feed
.get_metadata('a', 'a') == []
96 assert e
.getAttribute('foo') == 'bar'
97 self
.assertEqual(None, main_feed
.get_replaced_by())
100 local_path
= os
.path
.join(mydir
, 'Local.xml')
101 with
open(local_path
, 'rb') as stream
:
102 dom
= qdom
.parse(stream
)
103 feed
= model
.ZeroInstallFeed(dom
, local_path
= local_path
)
104 # (defaults to en-US if no language is set in the locale)
105 self
.assertEqual("Local feed (English)", feed
.summary
)
106 self
.assertEqual("English", feed
.description
)
108 self
.assertEqual(4, len(feed
.summaries
))
109 self
.assertEqual(2, len(feed
.descriptions
))
112 basetest
.test_locale
= ('es_ES', 'UTF8')
114 self
.assertEqual("Fuente local", feed
.summary
)
115 self
.assertEqual("Español", feed
.description
)
117 basetest
.test_locale
= ('en_GB', 'UTF8')
119 self
.assertEqual("Local feed (English GB)", feed
.summary
)
121 basetest
.test_locale
= ('fr_FR', 'UTF8')
123 self
.assertEqual("Local feed (English)", feed
.summary
)
124 self
.assertEqual("English", feed
.description
)
126 basetest
.test_locale
= (None, None)
128 def testCommand(self
):
129 local_path
= os
.path
.join(mydir
, 'Command.xml')
130 with
open(local_path
, 'rb') as stream
:
131 dom
= qdom
.parse(stream
)
132 feed
= model
.ZeroInstallFeed(dom
, local_path
= local_path
)
134 assert feed
.implementations
['a'].main
== 'foo'
135 assert feed
.implementations
['a'].commands
['run'].path
== 'foo'
136 assert feed
.implementations
['a'].commands
['test'].path
== 'test-foo'
138 assert feed
.implementations
['b'].main
== 'bar'
139 assert feed
.implementations
['b'].commands
['run'].path
== 'bar'
140 assert feed
.implementations
['b'].commands
['test'].path
== 'test-foo'
142 assert feed
.implementations
['c'].main
== 'test-gui'
143 assert feed
.implementations
['c'].commands
['run'].path
== 'test-gui'
144 assert feed
.implementations
['c'].commands
['test'].path
== 'test-baz'
146 def testStabPolicy(self
):
147 i
= model
.Interface('http://foo')
148 self
.assertEqual(None, i
.stability_policy
)
149 i
.set_stability_policy(model
.buggy
)
150 self
.assertEqual(model
.buggy
, i
.stability_policy
)
153 f
= model
.ZeroInstallFeed(None)
155 a
= model
.ZeroInstallImplementation(f
, 'foo', None)
157 assert a
.size
== a
.version
== a
.user_stability
== None
158 assert a
.arch
== a
.upstream_stability
== None
159 assert a
.dependencies
== {}
160 assert a
.download_sources
== []
161 assert a
.get_stability() is model
.testing
162 a
.upstream_stability
= model
.stable
163 assert a
.get_stability() is model
.stable
164 a
.user_stability
= model
.buggy
165 assert a
.get_stability() is model
.buggy
166 a
.version
= model
.parse_version('1.2.3')
167 self
.assertEqual('1.2.3', a
.get_version())
168 a
.version
= model
.parse_version('1.2.3-rc2-post')
169 self
.assertEqual('1.2.3-rc2-post', a
.get_version())
170 assert str(a
) == 'foo'
172 b
= model
.ZeroInstallImplementation(f
, 'foo', None)
173 b
.version
= model
.parse_version("1.2.1")
176 def testDownloadSource(self
):
177 f
= model
.ZeroInstallFeed(empty_feed
, local_path
= '/foo')
178 a
= model
.ZeroInstallImplementation(f
, 'foo', None)
179 a
.add_download_source('ftp://foo', 1024, None)
180 a
.add_download_source('ftp://foo.tgz', 1025, 'foo')
181 assert a
.download_sources
[0].url
== 'ftp://foo'
182 assert a
.download_sources
[0].size
== 1024
183 assert a
.download_sources
[0].extract
== None
186 def testEnvBind(self
):
187 a
= model
.EnvironmentBinding('PYTHONPATH', 'path')
188 assert a
.name
== 'PYTHONPATH'
189 assert a
.insert
== 'path'
192 def testEnvModes(self
):
193 prepend
= model
.EnvironmentBinding('PYTHONPATH', 'lib', None, model
.EnvironmentBinding
.PREPEND
)
194 assert prepend
.name
== 'PYTHONPATH'
195 assert prepend
.insert
== 'lib'
196 assert prepend
.mode
is model
.EnvironmentBinding
.PREPEND
198 self
.assertEqual('/impl/lib:/usr/lib', prepend
.get_value('/impl', '/usr/lib'))
199 self
.assertEqual('/impl/lib', prepend
.get_value('/impl', None))
201 append
= model
.EnvironmentBinding('PYTHONPATH', 'lib', '/opt/lib', model
.EnvironmentBinding
.APPEND
)
202 assert append
.name
== 'PYTHONPATH'
203 assert append
.insert
== 'lib'
204 assert append
.mode
is model
.EnvironmentBinding
.APPEND
206 self
.assertEqual('/usr/lib:/impl/lib', append
.get_value('/impl', '/usr/lib'))
207 self
.assertEqual('/opt/lib:/impl/lib', append
.get_value('/impl', None))
209 append
= model
.EnvironmentBinding('PYTHONPATH', 'lib', None, model
.EnvironmentBinding
.REPLACE
)
210 assert append
.name
== 'PYTHONPATH'
211 assert append
.insert
== 'lib'
212 assert append
.mode
is model
.EnvironmentBinding
.REPLACE
214 self
.assertEqual('/impl/lib', append
.get_value('/impl', '/usr/lib'))
215 self
.assertEqual('/impl/lib', append
.get_value('/impl', None))
217 assert model
.EnvironmentBinding('PYTHONPATH', 'lib').mode
== model
.EnvironmentBinding
.PREPEND
219 def testOverlay(self
):
220 for xml
, expected
in [(b
'<overlay/>', '<overlay . on />'),
221 (b
'<overlay src="usr"/>', '<overlay usr on />'),
222 (b
'<overlay src="package" mount-point="/usr/games"/>', '<overlay package on /usr/games>')]:
223 e
= qdom
.parse(BytesIO(xml
))
224 ol
= model
.process_binding(e
)
225 self
.assertEqual(expected
, str(ol
))
227 doc
= minidom
.parseString('<doc/>')
228 new_xml
= ol
._toxml
(doc
, None).toxml(encoding
= 'utf-8')
229 new_e
= qdom
.parse(BytesIO(new_xml
))
230 new_ol
= model
.process_binding(new_e
)
231 self
.assertEqual(expected
, str(new_ol
))
233 def testReplaced(self
):
234 local_path
= os
.path
.join(mydir
, 'Replaced.xml')
235 with
open(local_path
, 'rb') as stream
:
236 dom
= qdom
.parse(stream
)
237 feed
= model
.ZeroInstallFeed(dom
, local_path
= local_path
)
238 self
.assertEqual("http://localhost:8000/Hello", feed
.get_replaced_by())
241 b
= model
.InterfaceDependency('http://foo', element
= qdom
.Element(namespaces
.XMLNS_IFACE
, 'requires', {}))
242 assert not b
.restrictions
243 assert not b
.bindings
247 f
= model
.Feed('http://feed', arch
= None, user_override
= False)
248 assert f
.uri
== 'http://feed'
250 assert f
.machine
== None
251 assert f
.arch
== None
252 assert f
.user_override
== False
254 f
= model
.Feed('http://feed', arch
= 'Linux-*', user_override
= True)
255 assert f
.uri
== 'http://feed'
256 assert f
.os
== 'Linux'
257 assert f
.machine
== None
258 assert f
.arch
== 'Linux-*'
259 assert f
.user_override
== True
261 f
= model
.Feed('http://feed', arch
= '*-i386', user_override
= True)
262 assert f
.uri
== 'http://feed'
264 assert f
.machine
== 'i386'
265 assert f
.arch
== '*-i386'
266 assert f
.user_override
== True
267 assert str(f
).startswith('<Feed from')
270 f
= model
.Feed('http://feed', arch
= 'i386', user_override
= True)
272 except model
.SafeException
as ex
:
273 assert 'Malformed arch' in str(ex
)
275 def testCanonical(self
):
278 model
.canonical_iface_uri('http://foo')
280 except model
.SafeException
as ex
:
281 assert 'Missing /' in str(ex
)
283 self
.assertEqual('http://foo/',
284 model
.canonical_iface_uri('http://foo/'))
286 model
.canonical_iface_uri('bad-name')
288 except model
.SafeException
as ex
:
289 assert 'Bad interface name' in str(ex
)
292 model
.canonical_iface_uri('Command.xml')
294 model
.canonical_iface_uri('CommandMissing.xml')
296 except model
.SafeException
as ex
:
297 assert "Bad interface name 'CommandMissing.xml'" in str(ex
), ex
300 model
.canonical_iface_uri('file://{path}/Command.xml'.format(path
= mydir
))
302 model
.canonical_iface_uri('file://{path}/CommandMissing.xml'.format(path
= mydir
))
304 except model
.SafeException
as ex
:
305 assert "Bad interface name 'file://" in str(ex
), ex
308 model
.canonical_iface_uri('file:Command.xml')
310 model
.canonical_iface_uri('file:CommandMissing.xml')
312 except model
.SafeException
as ex
:
313 assert "Bad interface name 'file:CommandMissing.xml'" in str(ex
), ex
316 def testVersions(self
):
318 parsed
= model
.parse_version(v
)
319 assert model
.format_version(parsed
) == v
322 assert pv('1.0') > pv('0.9')
323 assert pv('1.0') > pv('1')
324 assert pv('1.0') == pv('1.0')
325 assert pv('0.9.9') < pv('1.0')
326 assert pv('10') > pv('2')
332 except model
.SafeException
:
341 assert pv('1') == [[1], 0]
342 assert pv('1.0') == [[1,0], 0]
343 assert pv('1.0-pre5') == [[1,0], -2, [5], 0]
344 assert pv('1.0-rc5') == [[1,0], -1, [5], 0]
345 assert pv('1.0-5') == [[1,0], 0, [5], 0]
346 assert pv('1.0-post5') == [[1,0], 1, [5], 0]
347 assert pv('1.0-post') == [[1,0], 1]
348 assert pv('1-rc2.0-pre2-post') == [[1], -1, [2,0], -2, [2], 1]
349 assert pv('1-rc2.0-pre-post') == [[1], -1, [2,0], -2, [], 1]
351 assert pv('1.0-0') > pv('1.0')
352 assert pv('1.0-1') > pv('1.0-0')
353 assert pv('1.0-0') < pv('1.0-1')
355 assert pv('1.0-pre99') > pv('1.0-pre1')
356 assert pv('1.0-pre99') < pv('1.0-rc1')
357 assert pv('1.0-rc1') < pv('1.0')
358 assert pv('1.0') < pv('1.0-0')
359 assert pv('1.0-0') < pv('1.0-post')
360 assert pv('2.1.9-pre-1') > pv('2.1.9-pre')
362 assert pv('2-post999') < pv('3-pre1')
364 if __name__
== '__main__':