3
# test DistUtilsExtra.auto
5
import sys, unittest, shutil, tempfile, os, os.path, subprocess, re
7
class T(unittest.TestCase):
9
self.src = tempfile.mkdtemp()
11
self._mksrc('setup.py', '''
12
from DistUtilsExtra.auto import setup
17
description='Test suite package',
18
url='https://foo.example.com',
19
license='GPL v2 or later',
21
author_email='martin.pitt@example.com',
25
self.install_tree = None
29
# check that setup.py clean removes everything
30
(o, e, s) = self.setup_py(['clean', '-a'])
31
self.assertEqual(s, 0)
32
cruft = self.diff_snapshot()
33
self.assertEqual(cruft, '', 'no cruft after cleaning:\n' + cruft)
35
shutil.rmtree(self.src)
37
shutil.rmtree(self.snapshot)
39
shutil.rmtree(self.install_tree)
42
self.install_tree = None
45
# actual tests come here
49
'''empty source tree (just setup.py)'''
51
(o, e, s) = self.do_install()
52
self.assertEqual(e, '')
53
self.assertEqual(s, 0)
54
self.failIf('following files are not recognized' in o)
56
f = self.installed_files()
57
# just installs the .egg_info
58
self.assertEqual(len(f), 1)
59
self.assert_(f[0].endswith('.egg-info'))
62
'''Ignores revision control files'''
64
self._mksrc('.shelf/1')
65
self._mksrc('.bzr/revs')
66
self._mksrc('.git/config')
67
self._mksrc('.svn/revs')
69
(o, e, s) = self.do_install()
70
self.assertEqual(e, '')
71
self.assertEqual(s, 0)
72
self.failIf('following files are not recognized' in o)
74
f = self.installed_files()
75
# just installs the .egg_info
76
self.assertEqual(len(f), 1)
77
self.assert_(f[0].endswith('.egg-info'))
79
def test_modules(self):
82
self._mksrc('yesme.py')
83
self._mksrc('stuff/notme.py')
85
(o, e, s) = self.do_install()
86
self.assertEqual(e, '')
87
self.assertEqual(s, 0)
88
self.assert_('following files are not recognized' in o)
89
self.assert_('\n stuff/notme.py\n' in o)
91
f = '\n'.join(self.installed_files())
92
self.assert_('-packages/yesme.py' in f)
93
self.failIf('notme' in f)
95
def test_packages(self):
98
self._mksrc('foopkg/__init__.py', '')
99
self._mksrc('foopkg/bar.py')
100
self._mksrc('foopkg/baz.py')
101
self._mksrc('noinit/notme.py')
103
(o, e, s) = self.do_install()
104
self.assertEqual(e, '')
105
self.assertEqual(s, 0)
106
self.assert_('following files are not recognized' in o)
107
self.assert_('\n noinit/notme.py\n' in o)
109
f = '\n'.join(self.installed_files())
110
self.assert_('foopkg/__init__.py' in f)
111
self.assert_('foopkg/bar.py' in f)
112
self.failIf('noinit' in f)
115
'''D-BUS configuration and service files'''
117
# D-BUS ACL configuration file
118
self._mksrc('daemon/com.example.foo.conf', '''<!DOCTYPE busconfig PUBLIC
119
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
120
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
124
# non-D-BUS configuration file
125
self._mksrc('daemon/defaults.conf', 'start = True\nlog = syslog')
127
# D-BUS system service
128
self._mksrc('daemon/com.example.foo.service', '''[D-BUS Service]
130
Exec=/usr/lib/foo/foo_daemon
133
# D-BUS session service
134
self._mksrc('gui/com.example.foo.gui.service', '''[D-BUS Service]
135
Name=com.example.Foo.GUI
136
Exec=/usr/bin/foo-gtk
139
# non-D-BUS .service file
140
self._mksrc('stuff/super.service', 'I am a file')
142
(o, e, s) = self.do_install()
143
self.assertEqual(e, '')
144
self.assertEqual(s, 0)
145
self.assert_('following files are not recognized' in o)
146
self.assert_('\n stuff/super.service\n' in o)
148
f = self.installed_files()
149
self.assertEqual(len(f), 4) # 3 D-BUS files plus .egg-info
150
self.assert_('/etc/dbus-1/system.d/com.example.foo.conf' in f)
151
self.assert_('/usr/share/dbus-1/system-services/com.example.foo.service' in f)
152
self.assert_('/usr/share/dbus-1/services/com.example.foo.gui.service' in f)
153
self.failIf('super.service' in '\n'.join(f))
155
def test_apport_hook(self):
158
self._mksrc('apport/foo.py', '''import os, apport
159
def add_info(report):
163
self._mksrc('apport/source_foo.py', '''import os, apport
164
def add_info(report):
168
(o, e, s) = self.do_install()
169
self.failIf('following files are not recognized' in o, o)
171
f = self.installed_files()
172
self.assertEqual(len(f), 3, f) # 2 hook files plus .egg-info
173
self.assert_('/usr/share/apport/package-hooks/foo.py' in f, f)
174
self.assert_('/usr/share/apport/package-hooks/source_foo.py' in f, f)
177
'''gettext *.po files'''
181
(o, e, s) = self.do_install()
182
self.assertEqual(e, '')
183
self.assertEqual(s, 0)
184
self.failIf('following files are not recognized' in o)
185
f = self.installed_files()
186
self.assert_('/usr/share/locale/de/LC_MESSAGES/foo.mo' in f)
187
self.assert_('/usr/share/locale/fr/LC_MESSAGES/foo.mo' in f)
188
self.failIf('junk' in '\n'.join(f))
190
msgunfmt = subprocess.Popen(['msgunfmt',
191
os.path.join(self.install_tree,
192
'usr/share/locale/de/LC_MESSAGES/foo.mo')],
193
stdout=subprocess.PIPE)
194
out = msgunfmt.communicate()[0].decode()
195
self.assertEqual(out, open(os.path.join(self.src, 'po/de.po')).read())
197
def test_policykit(self):
198
'''*.policy.in PolicyKit files'''
200
self._mksrc('daemon/com.example.foo.policy.in', '''<?xml version="1.0" encoding="UTF-8"?>
201
<!DOCTYPE policyconfig PUBLIC
202
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
203
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
205
<vendor>Foo project</vendor>
206
<vendor_url>https://foo.example.com</vendor_url>
208
<action id="com.example.foo.greet">
209
<_description>Good morning</_description>
210
<_message>Hello</_message>
212
<allow_active>yes</allow_active>
218
(o, e, s) = self.do_install()
219
self.assertEqual(e, '')
220
self.assertEqual(s, 0)
221
self.failIf('following files are not recognized' in o)
223
f = self.installed_files()
224
self.assert_('/usr/share/PolicyKit/policy/com.example.foo.policy' in f)
225
p = open(os.path.join(self.install_tree,
226
'usr/share/PolicyKit/policy/com.example.foo.policy')).read()
227
self.assert_('<description>Good morning</description>' in p)
228
self.assert_('<description xml:lang="de">Guten Morgen</description>' in p)
229
self.assert_('<message>Hello</message>' in p)
230
self.assert_('<message xml:lang="de">Hallo</message>' in p)
233
self._mksrc('foo.py', '''polkit = dbus.Interface(dbus.SystemBus().get_object(
234
'org.freedesktop.PolicyKit1',
235
'/org/freedesktop/PolicyKit1/Authority', False),
236
'org.freedesktop.PolicyKit1.Authority')
238
self.setup_py(['clean', '-a'])
240
(o, e, s) = self.do_install()
241
self.assertEqual(e, '')
242
self.assertEqual(s, 0)
243
self.failIf('following files are not recognized' in o)
245
f = self.installed_files()
246
self.failIf('/usr/share/PolicyKit/policy/com.example.foo.policy' in f)
247
self.assert_('/usr/share/polkit-1/actions/com.example.foo.policy' in f)
249
def test_desktop(self):
250
'''*.desktop.in files'''
252
self._mksrc('gui/foogtk.desktop.in', '''[Desktop Entry]
254
_Comment=Good morning
256
self._mksrc('gui/autostart/fooapplet.desktop.in', '''[Desktop Entry]
258
_Comment=Good morning
259
Exec=/usr/bin/fooapplet''')
261
self._mksrc('data/foosettings.desktop.in', '''[Desktop Entry]
263
_Comment=Good morning
264
Exec=/bin/foosettings''')
266
(o, e, s) = self.do_install()
267
self.assertEqual(e, '')
268
self.assertEqual(s, 0)
269
self.failIf('following files are not recognized' in o)
271
f = self.installed_files()
272
self.assert_('/usr/share/autostart/fooapplet.desktop' in f)
273
self.assert_('/usr/share/applications/foogtk.desktop' in f)
274
self.assert_('/usr/share/applications/foosettings.desktop' in f)
275
# data/*.desktop.in shouldn't go to data dir
276
self.failIf('/usr/share/foo/' in f)
278
p = open(os.path.join(self.install_tree,
279
'usr/share/autostart/fooapplet.desktop')).read()
280
self.assert_('\nName=Hello\n' in p)
281
self.assert_('\nName[de]=Hallo\n' in p)
282
self.assert_('\nComment[fr]=Bonjour\n' in p)
284
def test_icons(self):
287
self._mksrc('data/icons/scalable/actions/press.png')
288
self._mksrc('data/icons/48x48/apps/foo.png')
289
action_icon_path = os.path.join(self.src, 'data', 'icons', 'scalable',
291
os.symlink(os.path.join(action_icon_path, 'press.png'),
292
os.path.join(action_icon_path, 'crunch.png'))
294
(o, e, s) = self.do_install()
295
self.assertEqual(e, '')
296
self.assertEqual(s, 0)
297
self.failIf('following files are not recognized' in o)
299
f = self.installed_files()
300
self.assert_('/usr/share/icons/hicolor/scalable/actions/press.png' in f)
301
self.assert_('/usr/share/icons/hicolor/scalable/actions/crunch.png' in f)
302
self.assert_('/usr/share/icons/hicolor/48x48/apps/foo.png' in f)
303
self.assert_(os.path.islink(os.path.join(self.install_tree,
304
'usr/share/icons/hicolor/scalable/actions/crunch.png')))
307
'''Auxiliary files in data/'''
309
# have some explicitly covered files, to check that they don't get
310
# installed into prefix/share/foo/ again
311
self._mksrc('setup.py', '''
312
from DistUtilsExtra.auto import setup
313
from glob import glob
318
description='Test suite package',
319
url='https://foo.example.com',
320
license='GPL v2 or later',
321
author='Martin Pitt',
322
author_email='martin.pitt@example.com',
325
('/lib/udev/rules.d', ['data/40-foo.rules']),
326
('/etc/foo', glob('data/*.conf')),
331
self._mksrc('data/stuff')
332
self._mksrc('data/handlers/red.py', 'import sys\nprint ("RED")')
333
self._mksrc('data/handlers/blue.py', 'import sys\nprint ("BLUE")')
334
self._mksrc('data/40-foo.rules')
335
self._mksrc('data/blob1.conf')
336
self._mksrc('data/blob2.conf')
337
os.symlink('stuff', os.path.join(self.src, 'data', 'stufflink'))
339
(o, e, s) = self.do_install()
340
self.assertEqual(e, '')
341
self.assertEqual(s, 0)
342
self.failIf('following files are not recognized' in o)
344
f = self.installed_files()
345
self.assert_('/usr/share/foo/stuff' in f)
346
self.assert_('/usr/share/foo/stufflink' in f)
347
self.assert_(os.path.islink(os.path.join(self.install_tree, 'usr',
348
'share', 'foo', 'stufflink')))
349
self.assert_('/usr/share/foo/handlers/red.py' in f)
350
self.assert_('/usr/share/foo/handlers/blue.py' in f)
351
self.assert_('/lib/udev/rules.d/40-foo.rules' in f)
352
self.assert_('/etc/foo/blob1.conf' in f)
353
self.assert_('/etc/foo/blob2.conf' in f)
354
self.failIf('/usr/share/foo/blob1.conf' in f)
355
self.failIf('/usr/share/foo/40-foo.rules' in f)
357
def test_scripts(self):
360
# these should get autoinstalled
361
self._mksrc('bin/yell', '#!/bin/sh', True)
362
self._mksrc('bin/shout', '#!/bin/sh', True)
363
self._mksrc('bin/foo', '#!/bin/sh', True)
364
os.symlink('shout', os.path.join(self.src, 'bin', 'shoutlink'))
367
self._mksrc('daemon/food', '#!/bin/sh', True) # not in bin/
368
self._mksrc('foob', '#!/bin/sh', True) # not named like project
369
self._mksrc('bin/whisper', '#!/bin/sh') # not executable
371
(o, e, s) = self.do_install()
372
self.assertEqual(e, '')
373
self.assertEqual(s, 0)
374
self.assert_('following files are not recognized' in o)
375
self.assert_('\n foob' in o)
376
self.assert_('\n bin/whisper' in o)
377
self.assert_('\n daemon/food' in o)
379
f = self.installed_files()
380
self.assert_('/usr/bin/yell' in f)
381
self.assert_('/usr/bin/shout' in f)
382
self.assert_('/usr/bin/shoutlink' in f)
383
self.assert_(os.path.islink(os.path.join(self.install_tree, 'usr',
384
'bin', 'shoutlink')))
385
self.assert_('/usr/bin/foo' in f)
387
self.failIf('food' in ftext)
388
self.failIf('foob' in ftext)
389
self.failIf('whisper' in ftext)
391
# verify that they are executable
392
binpath = os.path.join(self.install_tree, 'usr', 'bin')
393
self.assert_(os.access(os.path.join(binpath, 'yell'), os.X_OK))
394
self.assert_(os.access(os.path.join(binpath, 'shout'), os.X_OK))
395
self.assert_(os.access(os.path.join(binpath, 'foo'), os.X_OK))
397
def test_pot_manual(self):
398
'''PO template creation with manual POTFILES.in'''
400
self._mk_i18n_source()
401
self._mksrc('po/foo.pot', '')
402
# only do a subset here
403
self._mksrc('po/POTFILES.in', '''
406
[type: gettext/glade]gtk/test.ui''')
408
(o, e, s) = self.setup_py(['build'])
409
self.assertEqual(e, '')
410
self.assertEqual(s, 0)
411
# POT file should not be shown as not recognized
412
self.failIf('\n po/foo.pot\n' in o)
414
pot_path = os.path.join(self.src, 'po', 'foo.pot')
415
self.assert_(os.path.exists(pot_path))
416
pot = open(pot_path).read()
418
self.failIf('msgid "no"' in pot)
419
self.assert_('msgid "yes1"' in pot)
420
self.assert_('msgid "yes2 %s"' in pot)
421
self.failIf('msgid "yes5"' in pot) # we didn't add helpers.py
422
self.assert_('msgid "yes7"' in pot) # we did include the desktop file
423
self.failIf('msgid "yes5"' in pot) # we didn't add helpers.py
424
self.assert_('msgid "yes11"' in pot) # we added one GTKBuilder file
425
self.failIf('msgid "yes12"' in pot) # ... but not the other
427
def test_pot_auto(self):
428
'''PO template creation with automatic POTFILES.in'''
430
self._mk_i18n_source()
432
(o, e, s) = self.setup_py(['build'])
433
self.assertEqual(e, '')
434
self.assertEqual(s, 0)
435
# POT file should not be shown as not recognized
436
self.failIf('\n po/foo.pot\n' in o)
438
pot_path = os.path.join(self.src, 'po', 'foo.pot')
439
self.assert_(os.path.exists(pot_path))
440
pot = open(pot_path).read()
442
self.failIf('msgid "no"' in pot)
443
for i in range(2, 15):
444
self.assert_('msgid "yes%i' % i in pot or
445
'msgid ""\n"yes%i' % i in pot,
447
# above loop would match yes11 to yes1 as well, so test it explicitly
448
self.assert_('msgid "yes1"' in pot)
450
def test_pot_auto_explicit(self):
451
'''PO template creation with automatic POTFILES.in and explicit scripts'''
453
self._mk_i18n_source()
455
# add some additional binaries here which aren't caught by default
456
self._mksrc('cli/client-cli', "#!/usr/bin/python\nprint (_('yes15'))", True)
457
self._mksrc('gtk/client-gtk', '#!/usr/bin/python\nprint (_("yes16"))', True)
458
# this is the most tricky case: intltool doesn't consider them Python
459
# files by default and thus just looks for _(""):
460
self._mksrc('kde/client-kde', "#!/usr/bin/python\nprint (_('yes17'))", True)
461
self._mksrc('po/POTFILES.in.in', 'gtk/client-gtk\nkde/client-kde')
462
self._mksrc('setup.py', '''
463
from DistUtilsExtra.auto import setup
468
data_files=[('share/foo', ['gtk/client-gtk', 'kde/client-kde'])],
469
scripts=['cli/client-cli'],
473
(o, e, s) = self.setup_py(['build'])
474
self.assertEqual(e, '')
475
self.assertEqual(s, 0)
476
# POT file should not be shown as not recognized
477
self.failIf('\n po/foo.pot\n' in o)
479
pot_path = os.path.join(self.src, 'po', 'foo.pot')
480
self.assert_(os.path.exists(pot_path))
481
pot = open(pot_path).read()
483
self.failIf('msgid "no"' in pot)
484
for i in range(2, 18):
485
self.assert_('msgid "yes%i' % i in pot or
486
'msgid ""\n"yes%i' % i in pot,
488
# above loop would match yes11 to yes1 as well, so test it explicitly
489
self.assert_('msgid "yes1"' in pot)
491
def test_standard_files(self):
492
'''Standard files (MANIFEST.in, COPYING, etc.)'''
494
self._mksrc('AUTHORS')
495
self._mksrc('COPYING')
496
self._mksrc('LICENSE')
497
self._mksrc('COPYING.LIB')
498
self._mksrc('README.txt')
499
self._mksrc('MANIFEST.in')
500
self._mksrc('MANIFEST')
504
(o, e, s) = self.do_install()
505
self.assertEqual(e, '')
506
self.assertEqual(s, 0)
507
self.failIf('following files are not recognized' in o, o)
509
f = self.installed_files()
510
self.assert_('/usr/share/doc/foo/README.txt' in f)
511
self.assert_('/usr/share/doc/foo/NEWS' in f)
513
self.failIf('MANIFEST' in ftext)
514
self.failIf('COPYING' in ftext)
515
self.failIf('COPYING' in ftext)
516
self.failIf('AUTHORS' in ftext)
517
self.failIf('TODO' in ftext)
519
# sub-dir READMEs shouldn't be installed by default
521
self._mksrc('extra/README')
522
(o, e, s) = self.do_install()
523
self.assertEqual(e, '')
524
self.assertEqual(s, 0)
525
self.assert_('following files are not recognized' in o)
526
self.assert_('\n extra/README\n' in o)
528
def test_sdist(self):
529
'''default MANIFEST'''
531
good = ['AUTHORS', 'README.txt', 'COPYING', 'helpers.py',
532
'foo/__init__.py', 'foo/bar.py', 'tests/all.py',
533
'gui/x.desktop.in', 'backend/foo.policy.in',
534
'daemon/backend.conf', 'x/y', 'po/de.po', 'po/foo.pot',
535
'.quickly', 'data/icons/16x16/apps/foo.png', 'bin/foo',
536
'backend/food', 'backend/com.example.foo.service',
537
'gtk/main.glade', 'dist/extra.tar.gz']
538
bad = ['po/de.mo', '.helpers.py.swp', '.bzr/index', '.svn/index',
539
'.git/index', 'bin/foo~', 'backend/foo.pyc',
540
'dist/foo-0.1.tar.gz', '.shelf/1', '.bzr/revs', '.git/config']
545
(o, e, s) = self.setup_py(['sdist', '-o'])
546
self.assert_("'MANIFEST.in' does not exist" in e)
547
self.assertEqual(s, 0)
549
manifest = open(os.path.join(self.src, 'MANIFEST')).read().splitlines()
552
self.assert_(f in manifest, '%s in manifest' % f)
554
self.failIf(f in manifest, '%s not in manifest' % f)
555
os.unlink(os.path.join(self.src, 'MANIFEST'))
557
def test_gtkbuilder(self):
558
'''GtkBuilder *.ui'''
560
self._mksrc('gtk/test.ui', '''<?xml version="1.0"?>
562
<requires lib="gtk+" version="2.16"/>
563
<object class="GtkWindow" id="window1">
564
<property name="title" translatable="yes">yes11</property>
565
<child><placeholder/></child>
569
self._mksrc('gtk/settings.ui', '''<?xml version="1.0"?>
570
<interface domain="foobar">
571
<requires lib="gtk+" version="2.16"/>
572
<object class="GtkWindow" id="window2">
573
<property name="title" translatable="yes">yes12</property>
574
<child><placeholder/></child>
578
self._mksrc('someweird.ui')
580
(o, e, s) = self.do_install()
581
self.assertEqual(e, '')
582
self.assertEqual(s, 0)
583
self.assert_('following files are not recognized' in o)
584
self.assert_('\n someweird.ui\n' in o)
586
f = self.installed_files()
587
self.assert_('/usr/share/foo/test.ui' in f)
588
self.assert_('/usr/share/foo/settings.ui' in f)
590
self.failIf('someweird' in ftext)
592
def test_manpages(self):
595
self._mksrc('man/foo.1', '.TH foo 1 "Jan 01, 1900" "Joe Developer"')
596
self._mksrc('daemon/food.8', '.TH food 8 "Jan 01, 1900" "Joe Developer"')
597
self._mksrc('cruft/food.1', '')
598
self._mksrc('daemon/notme.s', '.TH food 8 "Jan 01, 1900" "Joe Developer"')
600
(o, e, s) = self.do_install()
601
self.assertEqual(e, '')
602
self.assertEqual(s, 0)
603
self.assert_('following files are not recognized' in o)
604
self.assert_('\n cruft/food.1\n' in o)
605
self.assert_('\n daemon/notme.s\n' in o)
607
f = self.installed_files()
608
self.assert_('/usr/share/man/man1/foo.1' in f)
609
self.assert_('/usr/share/man/man8/food.8' in f)
611
self.failIf('food.1' in ftext)
612
self.failIf('notme' in ftext)
617
self._mksrc('etc/cron.daily/foo')
618
self._mksrc('etc/foo.conf')
619
self._mksrc('etc/init.d/foo', executable=True)
620
d = os.path.join(self.src, 'etc', 'cron.weekly')
622
os.symlink(os.path.join('..', 'cron.daily', 'foo'),
623
os.path.join(d, 'foo'))
625
(o, e, s) = self.do_install()
626
self.assertEqual(e, '')
627
self.assertEqual(s, 0)
628
self.failIf('following files are not recognized' in o, o)
630
f = self.installed_files()
631
self.assert_('/etc/cron.daily/foo' in f)
632
self.assert_('/etc/cron.weekly/foo' in f)
633
self.assert_('/etc/init.d/foo' in f)
634
self.assert_('/etc/foo.conf' in f)
636
# verify that init script is executable
637
self.assert_(os.access(os.path.join(self.install_tree, 'etc', 'init.d',
639
# verify that symlinks get preserved
640
self.assert_(os.path.islink(os.path.join(self.install_tree, 'etc',
641
'cron.weekly', 'foo')))
643
# check that we can install again into the same source tree
644
(o, e, s) = self.setup_py(['install', '--no-compile', '--prefix=/usr',
645
'--root=' + self.install_tree])
646
self.assertEqual(e, '')
647
self.assertEqual(s, 0)
648
self.failIf('following files are not recognized' in o, o)
650
def test_requires_provides(self):
651
'''automatic requires/provides'''
654
__import__('pkg_resources')
655
__import__('httplib2')
657
self.fail('You need to have pkg_resources and httplib2 installed for this test suite to work')
659
self._mksrc('foo/__init__.py', '')
660
self._mksrc('foo/stuff.py', '''import xml.parsers.expat
661
import os, os.path, email.mime, distutils.command.register
662
from email import header as h
663
import httplib2.iri2uri, unknown
666
self._mksrc('foo/bar/__init__.py', '')
667
self._mksrc('foo/bar/poke.py', 'def x(): pass')
669
self._mksrc('mymod.py', 'import foo\nfrom foo.bar.poke import x')
671
self._mksrc('bin/foo-cli', '''#!/usr/bin/python
675
from httplib2 import iri2uri
677
print ('import iamnota.module')
678
''', executable=True)
680
# this shouldn't be treated specially
681
self._mksrc('data/example-code/template.py', 'import example.module')
682
self._mksrc('data/example-code/mymod/__init__.py', '')
683
self._mksrc('data/example-code/mymod/shiny.py', 'import example.othermod')
685
(o, e, s) = self.do_install()
686
self.assertEqual(s, 0)
687
self.assertEqual(e, 'ERROR: Python module unknown not found\n')
688
self.failIf('following files are not recognized' in o)
690
inst = self.installed_files()
691
self.assert_('/usr/share/foo/example-code/template.py' in inst)
692
self.assert_('/usr/share/foo/example-code/mymod/shiny.py' in inst)
694
if 'template.py' in f or 'shiny' in f:
695
self.failIf('packages' in f)
698
(o, e, s) = self.setup_py(['install_egg_info', '-d', self.install_tree])
699
self.assertEqual(e, 'ERROR: Python module unknown not found\n')
700
egg = open(os.path.join(self.install_tree,
701
'foo-0.1.egg-info')).read().splitlines()
702
self.assert_('Name: foo' in egg)
705
prov = [prop.split(' ', 1)[1] for prop in egg if prop.startswith('Provides: ')]
706
self.assertEqual(set(prov), set(['foo', 'mymod']))
709
req = [prop.split(' ', 1)[1] for prop in egg if prop.startswith('Requires: ')]
710
self.assertEqual(set(req), set(['DistUtilsExtra.auto', 'httplib2', 'pkg_resources']))
713
'''Docbook XML help'''
715
self._mksrc('help/C/myprogram-C.omf')
716
self._mksrc('help/C/myprogram.xml')
717
self._mksrc('help/C/legal.xml')
718
self._mksrc('help/C/figures/mainscreen.png')
719
self._mksrc('help/de/myprogram-de.omf')
720
self._mksrc('help/de/myprogram.xml')
721
self._mksrc('help/de/legal.xml')
722
self._mksrc('help/de/figures/mainscreen.png')
724
self._mksrc('help/weird.xml')
725
self._mksrc('help/notme.png')
727
(o, e, s) = self.do_install()
728
self.assertEqual(e, '')
729
self.assertEqual(s, 0)
730
self.assert_('following files are not recognized' in o)
731
self.assert_('\n help/weird.xml\n' in o)
732
self.assert_('\n help/notme.png\n' in o)
734
f = self.installed_files()
735
self.assert_('/usr/share/omf/foo/myprogram-C.omf' in f)
736
self.assert_('/usr/share/omf/foo/myprogram-de.omf' in f)
737
self.assert_('/usr/share/gnome/help/foo/C/myprogram.xml' in f)
738
self.assert_('/usr/share/gnome/help/foo/C/legal.xml' in f)
739
self.assert_('/usr/share/gnome/help/foo/C/figures/mainscreen.png' in f)
740
self.assert_('/usr/share/gnome/help/foo/de/myprogram.xml' in f)
741
self.assert_('/usr/share/gnome/help/foo/de/legal.xml' in f)
742
self.assert_('/usr/share/gnome/help/foo/de/figures/mainscreen.png' in f)
748
def setup_py(self, args):
749
'''Run setup.py with given arguments.
751
For convenience, this snapshots the tree if no snapshot exists yet.
753
Return (out, err, exitcode) triple.
755
if not self.snapshot:
760
if 'PYTHONPATH' not in env:
761
env['PYTHONPATH'] = oldcwd
763
s = subprocess.Popen(['/proc/self/exe', 'setup.py'] + args, env=env,
764
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
765
(out, err) = s.communicate()
770
# python3 distutils bug workaround, filter out bogus errors
771
bogus_re = re.compile('^file .* \(for module .*\) not found$')
772
err = '\n'.join([l for l in err.splitlines() if not bogus_re.match(l)])
776
return (out, err, s.returncode)
778
def do_install(self):
779
'''Run setup.py install into temporary tree.
781
Return (out, err, exitcode) triple.
783
self.install_tree = tempfile.mkdtemp()
785
return self.setup_py(['install', '--no-compile', '--prefix=/usr',
786
'--root=' + self.install_tree])
788
def installed_files(self):
789
'''Return list of file paths in install tree.'''
792
for root, _, files in os.walk(self.install_tree):
793
assert root.startswith(self.install_tree)
794
r = root[len(self.install_tree):]
796
result.append(os.path.join(r, f))
799
def _mksrc(self, path, content=None, executable=False):
800
'''Create a file in the test source tree.'''
802
path = os.path.join(self.src, path)
803
dir = os.path.dirname(path)
804
if not os.path.isdir(dir):
808
# default content, to spot with diff
811
f.write(content + '\n')
815
os.chmod(path, 0o755)
817
def do_snapshot(self):
818
'''Snapshot source tree.
820
This should be called after a test set up all source files.
822
assert self.snapshot is None, 'snapshot already taken'
824
self.snapshot = tempfile.mkdtemp()
825
shutil.copytree(self.src, os.path.join(self.snapshot, 's'))
827
def diff_snapshot(self):
828
'''Compare source tree to snapshot.
830
Return diff -Nur output.
832
assert self.snapshot, 'no snapshot taken'
833
diff = subprocess.Popen(['diff', '-x', 'foo.pot', '-Nur', os.path.join(self.snapshot, 's'),
834
self.src], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
835
(out, err) = diff.communicate()
837
self.assertEqual(err, b'', 'diff error messages')
841
'''Create some example po files.'''
843
self._mksrc('po/POTFILES.in', '')
844
self._mksrc('po/de.po', '''msgid ""
845
msgstr "Content-Type: text/plain; charset=UTF-8\\n"
848
msgstr "Guten Morgen"
852
self._mksrc('po/fr.po', '''msgid ""
853
msgstr "Content-Type: text/plain; charset=UTF-8\\n"
858
def _mk_i18n_source(self):
859
'''Create some example source files with gettext calls'''
861
self._mksrc('gtk/main.py', '''print (_("yes1"))
870
self._mksrc('helpers.py', '''
882
self._mksrc('gui/foo.desktop.in', '''[Desktop Entry]
886
Exec=/usr/bin/foo''')
888
self._mksrc('daemon/com.example.foo.policy.in', '''<?xml version="1.0" encoding="UTF-8"?>
889
<!DOCTYPE policyconfig PUBLIC
890
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
891
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
893
<action id="com.example.foo.greet">
894
<_description>yes9</_description>
895
<_message>yes10</_message>
897
<allow_active>no6</allow_active>
902
self._mksrc('gtk/test.ui', '''<?xml version="1.0"?>
904
<requires lib="gtk+" version="2.16"/>
905
<object class="GtkWindow" id="window1">
906
<property name="title" translatable="yes">yes11</property>
907
<child><placeholder/></child>
911
self._mksrc('data/settings.ui', '''<?xml version="1.0"?>
912
<interface domain="foobar">
913
<requires lib="gtk+" version="2.16"/>
914
<object class="GtkWindow" id="window1">
915
<property name="title" translatable="yes">yes12</property>
916
<child><placeholder/></child>
920
self._mksrc('Makefile', 'echo _("no7")')
922
# Executables without *.py extension
923
self._mksrc('gtk/foo-gtk', '#!/usr/bin/python\nprint (_("yes13"))',
925
self._mksrc('cli/foo-cli', '#!/usr/bin/env python\nprint (_(\'yes14\'))',
927
self._mksrc('daemon/foobarize', '#!/usr/bin/flex\np _("no8")',