2 import sys
, os
, tempfile
, StringIO
3 from zeroinstall
.injector
.namespaces
import XMLNS_IFACE
4 from zeroinstall
.injector
.reader
import InvalidInterface
5 from zeroinstall
.injector
import model
, reader
, qdom
7 from xml
.dom
import minidom
9 sys
.path
.insert(0, '..')
11 import create
, merge
, release
13 header
= """<?xml version="1.0" ?>
14 <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface"
15 uri='http://test/hello.xml'>
17 <summary>for testing</summary>
18 <description>This is for testing.</description>
25 stream
= StringIO
.StringIO(xml
)
26 return model
.ZeroInstallFeed(qdom
.parse(stream
))
28 local_file
= os
.path
.join(os
.path
.dirname(__file__
), 'local.xml')
29 local_file_req
= os
.path
.join(os
.path
.dirname(__file__
), 'local-req.xml')
30 local_file_if
= os
.path
.join(os
.path
.dirname(__file__
), 'local-if.xml')
31 local_file_command
= os
.path
.join(os
.path
.dirname(__file__
), 'local-command.xml')
32 local_file_ns
= os
.path
.join(os
.path
.dirname(__file__
), 'local-ns.xml')
33 local_file_main_and_command
= os
.path
.join(os
.path
.dirname(__file__
), 'local-main-and-command.xml')
34 local_file_zi13
= os
.path
.join(os
.path
.dirname(__file__
), 'zeroinstall-injector-1.3.xml')
40 class TestLocal(unittest
.TestCase
):
42 master
= parse(create
.create_from_local(local_file
))
43 assert master
.url
== 'http://test/hello.xml', master
44 assert len(master
.implementations
) == 1
46 def testMergeFirst(self
):
47 master
= parse(merge
.merge(header
+ footer
, local_file
))
48 assert master
.url
== 'http://test/hello.xml', master
49 assert len(master
.implementations
) == 1
51 def testMergeSecond(self
):
52 master
= parse(merge
.merge(header
+ "<implementation id='sha1=123' version='1'/>" + footer
, local_file
))
53 assert master
.url
== 'http://test/hello.xml', master
54 assert len(master
.implementations
) == 2
56 def testMergeTwice(self
):
58 once
= merge
.merge(header
+ "<implementation id='sha1=123' version='1'/>" + footer
, local_file
)
59 twice
= merge
.merge(once
, local_file
)
61 except Exception as ex
:
62 assert 'Duplicate ID' in str(ex
)
64 def testMergeGroup(self
):
65 master
= parse(merge
.merge(header
+ "<group>\n <implementation id='sha1=123' version='1'/>\n </group>" + footer
, local_file
))
66 assert master
.url
== 'http://test/hello.xml', master
67 assert len(master
.implementations
) == 2
68 assert master
.implementations
['sha1=002'].requires
== []
70 def testMergeLocalReq(self
):
71 master
= parse(tap(merge
.merge(header
+ "<group x='x'>\n <implementation id='sha1=123' version='1'/>\n </group>" + footer
, local_file_req
)))
72 assert master
.url
== 'http://test/hello.xml', master
73 assert len(master
.implementations
) == 2
74 deps
= master
.implementations
['sha1=003'].requires
76 assert deps
[0].interface
== 'http://foo', deps
[0]
78 assert master
.implementations
['sha1=003'].metadata
['http://mynamespace/foo bob'] == 'bob'
80 def testNotSubset(self
):
81 master
= parse(merge
.merge(header
+ "<group a='a'>\n <implementation id='sha1=123' version='1'/>\n </group>" + footer
, local_file
))
82 assert master
.url
== 'http://test/hello.xml', master
83 assert len(master
.implementations
) == 2
84 assert master
.implementations
['sha1=123'].metadata
.get('a', None) == 'a'
85 assert master
.implementations
['sha1=002'].metadata
.get('a', None) == None
87 master
= parse(merge
.merge(header
+ """\n
89 <requires interface='http://foo' meta='foo'/>
90 <implementation id='sha1=004' version='1'/>
93 <requires interface='http://foo'>
96 <implementation id='sha1=001' version='1'/>
97 </group>""" + footer
, local_file_req
))
98 assert len(master
.implementations
['sha1=001'].requires
[0].restrictions
) == 1
99 assert len(master
.implementations
['sha1=003'].requires
[0].restrictions
) == 0
101 assert master
.implementations
['sha1=004'].requires
[0].metadata
.get('meta', None) == 'foo'
102 assert master
.implementations
['sha1=003'].requires
[0].metadata
.get('meta', None) == None
104 assert master
.implementations
['sha1=003'].main
== 'hello'
106 def testMergeBest(self
):
107 master_xml
= merge
.merge(header
+ """\n
109 <implementation id='sha1=123' version='1'/>
112 <requires interface='http://foo'/>
113 <implementation id='sha1=002' version='2'/>
114 </group>""" + footer
, local_file_req
)
115 master
= parse(master_xml
)
116 assert master
.url
== 'http://test/hello.xml', master
117 assert len(master
.implementations
) == 3
118 deps
= master
.implementations
['sha1=003'].requires
119 assert len(deps
) == 1
120 assert deps
[0].interface
== 'http://foo', deps
[0]
122 assert len(minidom
.parseString(master_xml
).documentElement
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 2
124 # Again, but with the groups the other way around
125 master_xml
= merge
.merge(header
+ """\n
127 <requires interface='http://foo'/>
128 <implementation id='sha1=002' version='2'/>
131 <implementation id='sha1=123' version='1'/>
132 </group>""" + footer
, local_file_req
)
133 master
= parse(master_xml
)
134 assert master
.url
== 'http://test/hello.xml', master
135 assert len(master
.implementations
) == 3
136 deps
= master
.implementations
['sha1=003'].requires
137 assert len(deps
) == 1
138 assert deps
[0].interface
== 'http://foo', deps
[0]
140 assert len(minidom
.parseString(master_xml
).documentElement
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 2
142 def testMergeNS(self
):
143 master_xml
= merge
.merge(header
+ footer
, local_file_ns
)
144 master
= parse(master_xml
)
145 assert master
.url
== 'http://test/hello.xml', master
146 assert len(master
.implementations
) == 1
147 commands
= master
.implementations
['sha1=003'].commands
148 assert len(commands
) == 1
149 assert commands
['run'].path
== 'run.sh', commands
['run'].path
151 new_root
= minidom
.parseString(master_xml
).documentElement
152 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 1
153 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'requires')) == 1
154 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'command')) == 1
156 foo_test
, = new_root
.getElementsByTagNameNS('http://mynamespace/foo', 'test')
157 foo1_test
, = new_root
.getElementsByTagNameNS('http://myother/foo', 'test')
159 def testMergeCommand(self
):
160 # We create a new group inside this one, sharing the <requires> and adding the <command>
161 master_xml
= merge
.merge(header
+ """
163 <requires interface='http://foo'>
164 <environment name='TESTING' value='true' mode='replace'/>
166 <implementation id='sha1=002' version='2'/>
167 </group>""" + footer
, local_file_command
)
168 master
= parse(master_xml
)
169 assert master
.url
== 'http://test/hello.xml', master
170 assert len(master
.implementations
) == 2
171 commands
= master
.implementations
['sha1=003'].commands
172 assert len(commands
) == 1
173 assert commands
['run'].path
== 'run.sh', commands
['run'].path
175 new_root
= minidom
.parseString(master_xml
).documentElement
176 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 2
177 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'requires')) == 1
178 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'command')) == 1
180 # We create a new top-level group inside this one, as we can't share the test command
181 master_xml
= merge
.merge(header
+ """
183 <requires interface='http://foo'>
184 <environment name='TESTING' value='true' mode='replace'/>
186 <command name='test' path='test.sh'/>
187 <implementation id='sha1=002' version='2'/>
188 </group>""" + footer
, local_file_command
)
189 master
= parse(master_xml
)
190 assert master
.url
== 'http://test/hello.xml', master
191 assert len(master
.implementations
) == 2
192 commands
= master
.implementations
['sha1=003'].commands
193 assert len(commands
) == 1
194 assert commands
['run'].path
== 'run.sh', commands
['run'].path
196 new_root
= minidom
.parseString(master_xml
).documentElement
197 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 2
198 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'requires')) == 2
199 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'command')) == 2
201 # We share the <requires> and override the <command>
202 master_xml
= merge
.merge(header
+ """
204 <requires interface='http://foo'>
205 <environment name='TESTING' value='true' mode='replace'/>
207 <command name='run' path='old-run.sh'/>
208 <implementation id='sha1=002' version='2'/>
209 </group>""" + footer
, local_file_command
)
210 master
= parse(master_xml
)
211 assert master
.url
== 'http://test/hello.xml', master
212 assert len(master
.implementations
) == 2
213 commands
= master
.implementations
['sha1=003'].commands
214 assert len(commands
) == 1
215 assert commands
['run'].path
== 'run.sh', commands
['run'].path
217 new_root
= minidom
.parseString(master_xml
).documentElement
218 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 2
219 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'requires')) == 1
220 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'command')) == 2
222 # We share the <requires> and the <command>
223 master_xml
= merge
.merge(header
+ """
225 <requires interface='http://foo'>
226 <environment name='TESTING' value='true' mode='replace'/>
228 <command name='run' path='run.sh'/>
229 <implementation id='sha1=002' version='2'/>
230 </group>""" + footer
, local_file_command
)
231 master
= parse(master_xml
)
232 assert master
.url
== 'http://test/hello.xml', master
233 assert len(master
.implementations
) == 2
234 commands
= master
.implementations
['sha1=003'].commands
235 assert len(commands
) == 1
236 assert commands
['run'].path
== 'run.sh', commands
['run'].path
238 new_root
= minidom
.parseString(master_xml
).documentElement
239 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'group')) == 1
240 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'requires')) == 1
241 assert len(new_root
.getElementsByTagNameNS(XMLNS_IFACE
, 'command')) == 1
243 def testMerge2(self
):
244 master_xml
= merge
.merge(header
+ """
245 <group license="OSI Approved :: GNU Lesser General Public License (LGPL)" main="0launch">
246 <command name="run" path="0launch">
247 <runner interface="http://repo.roscidus.com/python/python">
248 <version before="3"/>
253 <command name="run" path="0launch"/>
254 <implementation id="sha1new=7d1ecfbd76a42d56f029f9d0c72e4ac26c8561de" released="2011-07-23" version="1.2"/>
257 """ + footer
, local_file_zi13
)
258 doc
= minidom
.parseString(master_xml
)
260 n_groups
= len(doc
.getElementsByTagName("group"))
263 def testMergeMainAndCommand(self
):
264 # Ensure the main attribute doesn't get promoted over the command
266 # Case 1: the group already has a suitable main and command.
267 # We simply add the new implementation to the group, without its own main.
268 master_xml
= merge
.merge(header
+ """
270 <command name='run' path='run.sh'/>
271 <implementation id="sha1=001" version="0.1"/>
273 """ + footer
, local_file_main_and_command
)
274 feed
= parse(master_xml
)
276 assert feed
.implementations
['sha1=001'].main
== "run.sh"
277 assert feed
.implementations
['sha1=002'].main
== "run.sh"
279 # Case 2: the group doesn't specify a main.
280 # We need to create a sub-group for it.
281 master_xml
= merge
.merge(header
+ """
283 <command name='run' path='run.sh'/>
284 <implementation id="sha1=001" version="0.1"/>
286 """ + footer
, local_file_main_and_command
)
287 feed
= parse(master_xml
)
289 assert feed
.implementations
['sha1=001'].main
== "run.sh"
290 assert feed
.implementations
['sha1=002'].main
== "run.sh"
292 def testMergeIf0installVersion(self
):
293 master_xml
= merge
.merge(header
+ """
295 <command name='run' path='run.sh'/>
296 <implementation id="sha1=004" version="0.4"/>
298 """ + footer
, local_file_if
)
299 doc
= minidom
.parseString(master_xml
)
301 n_commands
= len(doc
.getElementsByTagName("command"))
302 assert n_commands
== 3
304 # We can share the run-old.sh <command>
305 master_xml
= merge
.merge(header
+ """
307 <command name='run' path='run-old.sh' if-0install-version='..!2'/>
308 <command name='run' path='run-mid.sh' if-0install-version='2..'/>
309 <implementation id="sha1=004" version="0.4"/>
311 """ + footer
, local_file_if
)
312 doc
= minidom
.parseString(master_xml
)
314 n_commands
= len(doc
.getElementsByTagName("command"))
315 assert n_commands
== 3
317 def testLocalContext(self
):
318 def get_context(xml_frag
):
319 doc
= minidom
.parseString(header
+ xml_frag
+ footer
)
320 impls
= list(doc
.getElementsByTagNameNS(XMLNS_IFACE
, 'implementation'))
321 assert len(impls
) == 1
322 return merge
.Context(impls
[0])
324 ctx
= get_context("<implementation id='sha1=001' version='1'/>")
325 assert ctx
.attribs
[(None, 'id')] == 'sha1=001'
326 assert ctx
.attribs
[(None, 'version')] == '1'
328 ctx
= get_context("<group t='t' x='1' y:z='2' xmlns:y='yns'><implementation id='sha1=001' version='1' t='r'/></group>")
329 assert ctx
.attribs
[(None, 'id')] == 'sha1=001'
330 assert ctx
.attribs
[(None, 'version')] == '1'
331 assert ctx
.attribs
[(None, 't')] == 'r'
332 assert ctx
.attribs
[(None, 'x')] == '1'
333 assert ctx
.attribs
[('yns', 'z')] == '2'
335 def testSetAtttibs(self
):
336 local_data
= open(local_file
).read()
337 result
= release
.set_attributes(local_data
, '0.2', id = 'sha1=98765', version
='3.7', main
= None)
338 feed
= model
.ZeroInstallFeed(qdom
.parse(StringIO
.StringIO(str(result
))), "local.xml")
339 assert len(feed
.implementations
) == 1
340 assert feed
.implementations
['sha1=98765'].get_version() == '3.7'
343 result
= release
.set_attributes(local_data
, '0.3', id = 'sha1=98765', version
='3.7', main
= None)
345 except Exception, ex
:
346 assert str(ex
) == 'No implementations with version=0.3'
348 suite
= unittest
.makeSuite(TestLocal
)
349 if __name__
== '__main__':