xmpedit

GTK+ editor for XMP metadata embedded in images
git clone https://code.djc.id.au/git/xmpedit/

test/guitest.py (6471B) - raw

      1 #!/usr/bin/env python
      2 
      3 import sys
      4 import os
      5 import time
      6 import struct
      7 import tempfile
      8 import subprocess
      9 import Xlib.display
     10 import dogtail.tree
     11 import unittest
     12 
     13 def extract_xmp(path):
     14     popen = subprocess.Popen([
     15             os.path.join('target', 'printxmp'), path],
     16             stdout=subprocess.PIPE)
     17     stdout, stderr = popen.communicate()
     18     assert popen.returncode == 0
     19     return stdout.decode('utf8')
     20 
     21 class XmpeditTestCase(unittest.TestCase):
     22 
     23     def start(self, image_filename):
     24         self.tempfile = tempfile.NamedTemporaryFile()
     25         self.tempfile.write(open(os.path.join('testdata', image_filename)).read())
     26         self.tempfile.flush()
     27         self.tempfile.seek(0)
     28         self.popen = subprocess.Popen(
     29                 [os.path.join('target', 'xmpedit'), self.tempfile.name],
     30                 env=dict(os.environ.items() + [
     31                     ('G_DEBUG', 'fatal_criticals'),
     32                     ('G_SLICE', 'debug-blocks'),
     33                     ('GNOME_DISABLE_CRASH_DIALOG', '1')
     34                 ]))
     35 
     36     def stop(self):
     37         if self.popen.returncode is None:
     38             print 'Terminating process under test'
     39             self.popen.terminate()
     40             self.popen.wait()
     41 
     42     def assert_stopped(self):
     43         for _ in range(3):
     44             if self.popen.poll() is not None:
     45                 assert self.popen.returncode == 0
     46                 return
     47             time.sleep(1)
     48         assert False, 'Process did not end'
     49     
     50     def assert_image_unmodified(self, image_filename):
     51         self.tempfile.seek(0)
     52         assert self.tempfile.read() == open(os.path.join('testdata', image_filename)).read(), 'Image should be unmodified'
     53 
     54     def get_window(self):
     55         root = Xlib.display.Display().screen().root # XXX multiple screens?
     56         for child in root.query_tree().children:
     57             if child.get_wm_class() is not None and 'xmpedit' in child.get_wm_class():
     58                 return child
     59     
     60     def close_window(self):
     61         window = self.get_window()
     62         assert window is not None, "Where'd the window go?"
     63         WM_PROTOCOLS = window.display.get_atom('WM_PROTOCOLS')
     64         WM_DELETE_WINDOW = window.display.get_atom('WM_DELETE_WINDOW')
     65         assert WM_DELETE_WINDOW in window.get_wm_protocols()
     66         event = Xlib.protocol.event.ClientMessage(window=window, client_type=WM_PROTOCOLS,
     67                 data=(32, struct.pack('=lllll', WM_DELETE_WINDOW, 0, 0, 0, 0)))
     68         window.send_event(event)
     69         window.display.flush()
     70     
     71 class Test(XmpeditTestCase):
     72 
     73     def setUp(self):
     74         self.start('24-06-06_1449.jpg')
     75 
     76     def tearDown(self):
     77         self.stop()
     78         
     79     def test_do_nothing(self):
     80         xmpedit = dogtail.tree.Root().application('xmpedit')
     81         window = xmpedit.child(roleName='frame')
     82         self.close_window()
     83         self.assert_stopped()
     84         self.assert_image_unmodified('24-06-06_1449.jpg')
     85     
     86     def test_close_without_saving(self):
     87         xmpedit = dogtail.tree.Root().application('xmpedit')
     88         window = xmpedit.child(roleName='frame')
     89         pe, = [child for child in window.child('Image properties').children
     90                 if child.name.splitlines()[0] == 'Description'] # ugh
     91         pe.select()
     92         entry = window.child(roleName='ROLE_TEXT', label='Description')
     93         entry.grabFocus()
     94         entry.text = 'new description'
     95         lang = window.child(roleName='ROLE_TEXT', label='Language:')
     96         lang.text = 'en'
     97         self.close_window()
     98         alert = xmpedit.child(roleName='alert')
     99         self.assertEquals(alert.child(roleName='label').name,
    100                 'Your changes to image "%s" have not been saved.\n\nSave changes before closing?'
    101                 % os.path.basename(self.tempfile.name))
    102         alert.button('Close without saving').doAction('click')
    103         self.assert_stopped()
    104         self.assert_image_unmodified('24-06-06_1449.jpg')
    105             
    106     def test_edit_then_revert(self):
    107         xmpedit = dogtail.tree.Root().application('xmpedit')
    108         window = xmpedit.child(roleName='frame')
    109         pe, = [child for child in window.child('Image properties').children
    110                 if child.name.splitlines()[0] == 'Description'] # ugh
    111         pe.select()
    112         entry = window.child(roleName='ROLE_TEXT', label='Description')
    113         entry.grabFocus()
    114         entry.text = 'new description'
    115         lang = window.child(roleName='ROLE_TEXT', label='Language:')
    116         lang.text = 'en'
    117         assert window.button('Revert').sensitive
    118         window.button('Revert').doAction('click')
    119         entry = window.child(roleName='ROLE_TEXT', label='Description')
    120         self.assertEquals(entry.text, 'Edward Scissorhands stencil graffiti '
    121                 'on the wall of John Hines building.')
    122         lang = window.child(roleName='ROLE_TEXT', label='Language:')
    123         self.assertEquals(lang.text, 'x-default')
    124         self.close_window()
    125         self.assert_stopped()
    126         self.assert_image_unmodified('24-06-06_1449.jpg')
    127 
    128     def test_update_description(self):
    129         xmpedit = dogtail.tree.Root().application('xmpedit')
    130         window = xmpedit.child(roleName='frame')
    131         pe, = [child for child in window.child('Image properties').children
    132                 if child.name.splitlines()[0] == 'Description'] # ugh
    133         pe.select()
    134         entry = window.child(roleName='ROLE_TEXT', label='Description')
    135         entry.grabFocus()
    136         entry.text = 'new description'
    137         lang = window.child(roleName='ROLE_TEXT', label='Language:')
    138         lang.text = 'en'
    139         assert window.button('Save').sensitive
    140         window.button('Save').doAction('click')
    141         self.close_window()
    142         self.assert_stopped()
    143         xmp = extract_xmp(self.tempfile.name)
    144         self.assertEquals(len(xmp), 2675)
    145         self.assertEquals(extract_xmp(self.tempfile.name),
    146                 u'''<?xpacket begin="\ufeff" id="W5M0MpCehiHzreSzNTczkc9d"?><x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="xmpedit 0.0-dev"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about=""><Iptc4xmlCore:Location xmlns:Iptc4xmlCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/">UQ St Lucia</Iptc4xmlCore:Location><dc:description xmlns:dc="http://purl.org/dc/elements/1.1/"><rdf:Alt><rdf:li xml:lang="en">new description</rdf:li></rdf:Alt></dc:description></rdf:Description></rdf:RDF></x:xmpmeta>''' + ' ' * 2143 + '''<?xpacket end="w"?>''')
    147 
    148 if __name__ == '__main__':
    149     unittest.main()