Home | History | Annotate | Download | only in test_ttk
      1 # -*- encoding: utf-8 -*-
      2 import sys
      3 import unittest
      4 import ttk
      5 
      6 class MockTclObj(object):
      7     typename = 'test'
      8 
      9     def __init__(self, val):
     10         self.val = val
     11 
     12     def __str__(self):
     13         return unicode(self.val)
     14 
     15 
     16 class MockStateSpec(object):
     17     typename = 'StateSpec'
     18 
     19     def __init__(self, *args):
     20         self.val = args
     21 
     22     def __str__(self):
     23         return ' '.join(self.val)
     24 
     25 
     26 class InternalFunctionsTest(unittest.TestCase):
     27 
     28     def test_format_optdict(self):
     29         def check_against(fmt_opts, result):
     30             for i in range(0, len(fmt_opts), 2):
     31                 self.assertEqual(result.pop(fmt_opts[i]), fmt_opts[i + 1])
     32             if result:
     33                 self.fail("result still got elements: %s" % result)
     34 
     35         # passing an empty dict should return an empty object (tuple here)
     36         self.assertFalse(ttk._format_optdict({}))
     37 
     38         # check list formatting
     39         check_against(
     40             ttk._format_optdict({'fg': 'blue', 'padding': [1, 2, 3, 4]}),
     41             {'-fg': 'blue', '-padding': '1 2 3 4'})
     42 
     43         # check tuple formatting (same as list)
     44         check_against(
     45             ttk._format_optdict({'test': (1, 2, '', 0)}),
     46             {'-test': '1 2 {} 0'})
     47 
     48         # check untouched values
     49         check_against(
     50             ttk._format_optdict({'test': {'left': 'as is'}}),
     51             {'-test': {'left': 'as is'}})
     52 
     53         # check script formatting
     54         check_against(
     55             ttk._format_optdict(
     56                 {'test': [1, -1, '', '2m', 0], 'test2': 3,
     57                  'test3': '', 'test4': 'abc def',
     58                  'test5': '"abc"', 'test6': '{}',
     59                  'test7': '} -spam {'}, script=True),
     60             {'-test': '{1 -1 {} 2m 0}', '-test2': '3',
     61              '-test3': '{}', '-test4': '{abc def}',
     62              '-test5': '{"abc"}', '-test6': r'\{\}',
     63              '-test7': r'\}\ -spam\ \{'})
     64 
     65         opts = {u'': True, u'': False}
     66         orig_opts = opts.copy()
     67         # check if giving unicode keys is fine
     68         check_against(ttk._format_optdict(opts), {u'-': True, u'-': False})
     69         # opts should remain unchanged
     70         self.assertEqual(opts, orig_opts)
     71 
     72         # passing values with spaces inside a tuple/list
     73         check_against(
     74             ttk._format_optdict(
     75                 {'option': ('one two', 'three')}),
     76             {'-option': '{one two} three'})
     77         check_against(
     78             ttk._format_optdict(
     79                 {'option': ('one\ttwo', 'three')}),
     80             {'-option': '{one\ttwo} three'})
     81 
     82         # passing empty strings inside a tuple/list
     83         check_against(
     84             ttk._format_optdict(
     85                 {'option': ('', 'one')}),
     86             {'-option': '{} one'})
     87 
     88         # passing values with braces inside a tuple/list
     89         check_against(
     90             ttk._format_optdict(
     91                 {'option': ('one} {two', 'three')}),
     92             {'-option': r'one\}\ \{two three'})
     93 
     94         # passing quoted strings inside a tuple/list
     95         check_against(
     96             ttk._format_optdict(
     97                 {'option': ('"one"', 'two')}),
     98             {'-option': '{"one"} two'})
     99         check_against(
    100             ttk._format_optdict(
    101                 {'option': ('{one}', 'two')}),
    102             {'-option': r'\{one\} two'})
    103 
    104         # ignore an option
    105         amount_opts = len(ttk._format_optdict(opts, ignore=(u''))) // 2
    106         self.assertEqual(amount_opts, len(opts) - 1)
    107 
    108         # ignore non-existing options
    109         amount_opts = len(ttk._format_optdict(opts, ignore=(u'', 'b'))) // 2
    110         self.assertEqual(amount_opts, len(opts) - 1)
    111 
    112         # ignore every option
    113         self.assertFalse(ttk._format_optdict(opts, ignore=opts.keys()))
    114 
    115 
    116     def test_format_mapdict(self):
    117         opts = {'a': [('b', 'c', 'val'), ('d', 'otherval'), ('', 'single')]}
    118         result = ttk._format_mapdict(opts)
    119         self.assertEqual(len(result), len(opts.keys()) * 2)
    120         self.assertEqual(result, ('-a', '{b c} val d otherval {} single'))
    121         self.assertEqual(ttk._format_mapdict(opts, script=True),
    122             ('-a', '{{b c} val d otherval {} single}'))
    123 
    124         self.assertEqual(ttk._format_mapdict({2: []}), ('-2', ''))
    125 
    126         opts = {u'd': [(u'', u'vl')]}
    127         result = ttk._format_mapdict(opts)
    128         self.assertEqual(result, (u'-d', u' vl'))
    129 
    130         # empty states
    131         valid = {'opt': [('', u'', 'hi')]}
    132         self.assertEqual(ttk._format_mapdict(valid), ('-opt', '{ } hi'))
    133 
    134         # when passing multiple states, they all must be strings
    135         invalid = {'opt': [(1, 2, 'valid val')]}
    136         self.assertRaises(TypeError, ttk._format_mapdict, invalid)
    137         invalid = {'opt': [([1], '2', 'valid val')]}
    138         self.assertRaises(TypeError, ttk._format_mapdict, invalid)
    139         # but when passing a single state, it can be anything
    140         valid = {'opt': [[1, 'value']]}
    141         self.assertEqual(ttk._format_mapdict(valid), ('-opt', '1 value'))
    142         # special attention to single states which evalute to False
    143         for stateval in (None, 0, False, '', set()): # just some samples
    144             valid = {'opt': [(stateval, 'value')]}
    145             self.assertEqual(ttk._format_mapdict(valid),
    146                 ('-opt', '{} value'))
    147 
    148         # values must be iterable
    149         opts = {'a': None}
    150         self.assertRaises(TypeError, ttk._format_mapdict, opts)
    151 
    152         # items in the value must have size >= 2
    153         self.assertRaises(IndexError, ttk._format_mapdict,
    154             {'a': [('invalid', )]})
    155 
    156 
    157     def test_format_elemcreate(self):
    158         self.assertTrue(ttk._format_elemcreate(None), (None, ()))
    159 
    160         ## Testing type = image
    161         # image type expects at least an image name, so this should raise
    162         # IndexError since it tries to access the index 0 of an empty tuple
    163         self.assertRaises(IndexError, ttk._format_elemcreate, 'image')
    164 
    165         # don't format returned values as a tcl script
    166         # minimum acceptable for image type
    167         self.assertEqual(ttk._format_elemcreate('image', False, 'test'),
    168             ("test ", ()))
    169         # specifying a state spec
    170         self.assertEqual(ttk._format_elemcreate('image', False, 'test',
    171             ('', 'a')), ("test {} a", ()))
    172         # state spec with multiple states
    173         self.assertEqual(ttk._format_elemcreate('image', False, 'test',
    174             ('a', 'b', 'c')), ("test {a b} c", ()))
    175         # state spec and options
    176         res = ttk._format_elemcreate('image', False, 'test',
    177                                      ('a', 'b'), a='x', b='y')
    178         self.assertEqual(res[0], "test a b")
    179         self.assertEqual(set(res[1]), {"-a", "x", "-b", "y"})
    180         # format returned values as a tcl script
    181         # state spec with multiple states and an option with a multivalue
    182         self.assertEqual(ttk._format_elemcreate('image', True, 'test',
    183             ('a', 'b', 'c', 'd'), x=[2, 3]), ("{test {a b c} d}", "-x {2 3}"))
    184 
    185         ## Testing type = vsapi
    186         # vsapi type expects at least a class name and a part_id, so this
    187         # should raise an ValueError since it tries to get two elements from
    188         # an empty tuple
    189         self.assertRaises(ValueError, ttk._format_elemcreate, 'vsapi')
    190 
    191         # don't format returned values as a tcl script
    192         # minimum acceptable for vsapi
    193         self.assertEqual(ttk._format_elemcreate('vsapi', False, 'a', 'b'),
    194             ("a b ", ()))
    195         # now with a state spec with multiple states
    196         self.assertEqual(ttk._format_elemcreate('vsapi', False, 'a', 'b',
    197             ('a', 'b', 'c')), ("a b {a b} c", ()))
    198         # state spec and option
    199         self.assertEqual(ttk._format_elemcreate('vsapi', False, 'a', 'b',
    200             ('a', 'b'), opt='x'), ("a b a b", ("-opt", "x")))
    201         # format returned values as a tcl script
    202         # state spec with a multivalue and an option
    203         self.assertEqual(ttk._format_elemcreate('vsapi', True, 'a', 'b',
    204             ('a', 'b', [1, 2]), opt='x'), ("{a b {a b} {1 2}}", "-opt x"))
    205 
    206         # Testing type = from
    207         # from type expects at least a type name
    208         self.assertRaises(IndexError, ttk._format_elemcreate, 'from')
    209 
    210         self.assertEqual(ttk._format_elemcreate('from', False, 'a'),
    211             ('a', ()))
    212         self.assertEqual(ttk._format_elemcreate('from', False, 'a', 'b'),
    213             ('a', ('b', )))
    214         self.assertEqual(ttk._format_elemcreate('from', True, 'a', 'b'),
    215             ('{a}', 'b'))
    216 
    217 
    218     def test_format_layoutlist(self):
    219         def sample(indent=0, indent_size=2):
    220             return ttk._format_layoutlist(
    221             [('a', {'other': [1, 2, 3], 'children':
    222                 [('b', {'children':
    223                     [('c', {'children':
    224                         [('d', {'nice': 'opt'})], 'something': (1, 2)
    225                     })]
    226                 })]
    227             })], indent=indent, indent_size=indent_size)[0]
    228 
    229         def sample_expected(indent=0, indent_size=2):
    230             spaces = lambda amount=0: ' ' * (amount + indent)
    231             return (
    232                 "%sa -other {1 2 3} -children {\n"
    233                 "%sb -children {\n"
    234                 "%sc -something {1 2} -children {\n"
    235                 "%sd -nice opt\n"
    236                 "%s}\n"
    237                 "%s}\n"
    238                 "%s}" % (spaces(), spaces(indent_size),
    239                     spaces(2 * indent_size), spaces(3 * indent_size),
    240                     spaces(2 * indent_size), spaces(indent_size), spaces()))
    241 
    242         # empty layout
    243         self.assertEqual(ttk._format_layoutlist([])[0], '')
    244 
    245         # smallest (after an empty one) acceptable layout
    246         smallest = ttk._format_layoutlist([('a', None)], indent=0)
    247         self.assertEqual(smallest,
    248             ttk._format_layoutlist([('a', '')], indent=0))
    249         self.assertEqual(smallest[0], 'a')
    250 
    251         # testing indentation levels
    252         self.assertEqual(sample(), sample_expected())
    253         for i in range(4):
    254             self.assertEqual(sample(i), sample_expected(i))
    255             self.assertEqual(sample(i, i), sample_expected(i, i))
    256 
    257         # invalid layout format, different kind of exceptions will be
    258         # raised
    259 
    260         # plain wrong format
    261         self.assertRaises(ValueError, ttk._format_layoutlist,
    262             ['bad', 'format'])
    263         self.assertRaises(TypeError, ttk._format_layoutlist, None)
    264         # _format_layoutlist always expects the second item (in every item)
    265         # to act like a dict (except when the value evalutes to False).
    266         self.assertRaises(AttributeError,
    267             ttk._format_layoutlist, [('a', 'b')])
    268         # bad children formatting
    269         self.assertRaises(ValueError, ttk._format_layoutlist,
    270             [('name', {'children': {'a': None}})])
    271 
    272 
    273     def test_script_from_settings(self):
    274         # empty options
    275         self.assertFalse(ttk._script_from_settings({'name':
    276             {'configure': None, 'map': None, 'element create': None}}))
    277 
    278         # empty layout
    279         self.assertEqual(
    280             ttk._script_from_settings({'name': {'layout': None}}),
    281             "ttk::style layout name {\nnull\n}")
    282 
    283         configdict = {u'': True, u'': False}
    284         self.assertTrue(
    285             ttk._script_from_settings({'name': {'configure': configdict}}))
    286 
    287         mapdict = {u'd': [(u'', u'vl')]}
    288         self.assertTrue(
    289             ttk._script_from_settings({'name': {'map': mapdict}}))
    290 
    291         # invalid image element
    292         self.assertRaises(IndexError,
    293             ttk._script_from_settings, {'name': {'element create': ['image']}})
    294 
    295         # minimal valid image
    296         self.assertTrue(ttk._script_from_settings({'name':
    297             {'element create': ['image', 'name']}}))
    298 
    299         image = {'thing': {'element create':
    300             ['image', 'name', ('state1', 'state2', 'val')]}}
    301         self.assertEqual(ttk._script_from_settings(image),
    302             "ttk::style element create thing image {name {state1 state2} val} ")
    303 
    304         image['thing']['element create'].append({'opt': 30})
    305         self.assertEqual(ttk._script_from_settings(image),
    306             "ttk::style element create thing image {name {state1 state2} val} "
    307             "-opt 30")
    308 
    309         image['thing']['element create'][-1]['opt'] = [MockTclObj(3),
    310             MockTclObj('2m')]
    311         self.assertEqual(ttk._script_from_settings(image),
    312             "ttk::style element create thing image {name {state1 state2} val} "
    313             "-opt {3 2m}")
    314 
    315 
    316     def test_dict_from_tcltuple(self):
    317         fakettuple = ('-a', '{1 2 3}', '-something', 'foo')
    318 
    319         self.assertEqual(ttk._dict_from_tcltuple(fakettuple, False),
    320             {'-a': '{1 2 3}', '-something': 'foo'})
    321 
    322         self.assertEqual(ttk._dict_from_tcltuple(fakettuple),
    323             {'a': '{1 2 3}', 'something': 'foo'})
    324 
    325         # passing a tuple with a single item should return an empty dict,
    326         # since it tries to break the tuple by pairs.
    327         self.assertFalse(ttk._dict_from_tcltuple(('single', )))
    328 
    329         sspec = MockStateSpec('a', 'b')
    330         self.assertEqual(ttk._dict_from_tcltuple(('-a', (sspec, 'val'))),
    331             {'a': [('a', 'b', 'val')]})
    332 
    333         self.assertEqual(ttk._dict_from_tcltuple((MockTclObj('-padding'),
    334             [MockTclObj('1'), 2, MockTclObj('3m')])),
    335             {'padding': [1, 2, '3m']})
    336 
    337 
    338     def test_list_from_statespec(self):
    339         def test_it(sspec, value, res_value, states):
    340             self.assertEqual(ttk._list_from_statespec(
    341                 (sspec, value)), [states + (res_value, )])
    342 
    343         states_even = tuple('state%d' % i for i in range(6))
    344         statespec = MockStateSpec(*states_even)
    345         test_it(statespec, 'val', 'val', states_even)
    346         test_it(statespec, MockTclObj('val'), 'val', states_even)
    347 
    348         states_odd = tuple('state%d' % i for i in range(5))
    349         statespec = MockStateSpec(*states_odd)
    350         test_it(statespec, 'val', 'val', states_odd)
    351 
    352         test_it(('a', 'b', 'c'), MockTclObj('val'), 'val', ('a', 'b', 'c'))
    353 
    354 
    355     def test_list_from_layouttuple(self):
    356         # empty layout tuple
    357         self.assertFalse(ttk._list_from_layouttuple(()))
    358 
    359         # shortest layout tuple
    360         self.assertEqual(ttk._list_from_layouttuple(('name', )),
    361             [('name', {})])
    362 
    363         # not so interesting ltuple
    364         sample_ltuple = ('name', '-option', 'value')
    365         self.assertEqual(ttk._list_from_layouttuple(sample_ltuple),
    366             [('name', {'option': 'value'})])
    367 
    368         # empty children
    369         self.assertEqual(ttk._list_from_layouttuple(
    370             ('something', '-children', ())),
    371             [('something', {'children': []})]
    372         )
    373 
    374         # more interesting ltuple
    375         ltuple = (
    376             'name', '-option', 'niceone', '-children', (
    377                 ('otherone', '-children', (
    378                     ('child', )), '-otheropt', 'othervalue'
    379                 )
    380             )
    381         )
    382         self.assertEqual(ttk._list_from_layouttuple(ltuple),
    383             [('name', {'option': 'niceone', 'children':
    384                 [('otherone', {'otheropt': 'othervalue', 'children':
    385                     [('child', {})]
    386                 })]
    387             })]
    388         )
    389 
    390         # bad tuples
    391         self.assertRaises(ValueError, ttk._list_from_layouttuple,
    392             ('name', 'no_minus'))
    393         self.assertRaises(ValueError, ttk._list_from_layouttuple,
    394             ('name', 'no_minus', 'value'))
    395         self.assertRaises(ValueError, ttk._list_from_layouttuple,
    396             ('something', '-children')) # no children
    397         self.assertRaises(ValueError, ttk._list_from_layouttuple,
    398             ('something', '-children', 'value')) # invalid children
    399 
    400 
    401     def test_val_or_dict(self):
    402         def func(opt, val=None):
    403             if val is None:
    404                 return "test val"
    405             return (opt, val)
    406 
    407         options = {'test': None}
    408         self.assertEqual(ttk._val_or_dict(options, func), "test val")
    409 
    410         options = {'test': 3}
    411         self.assertEqual(ttk._val_or_dict(options, func), options)
    412 
    413 
    414     def test_convert_stringval(self):
    415         tests = (
    416             (0, 0), ('09', 9), ('a', 'a'), (u'', u''), ([], '[]'),
    417             (None, 'None')
    418         )
    419         for orig, expected in tests:
    420             self.assertEqual(ttk._convert_stringval(orig), expected)
    421 
    422         if sys.getdefaultencoding() == 'ascii':
    423             self.assertRaises(UnicodeDecodeError,
    424                 ttk._convert_stringval, '')
    425 
    426 
    427 class TclObjsToPyTest(unittest.TestCase):
    428 
    429     def test_unicode(self):
    430         adict = {'opt': u'vl'}
    431         self.assertEqual(ttk.tclobjs_to_py(adict), {'opt': u'vl'})
    432 
    433         adict['opt'] = MockTclObj(adict['opt'])
    434         self.assertEqual(ttk.tclobjs_to_py(adict), {'opt': u'vl'})
    435 
    436     def test_multivalues(self):
    437         adict = {'opt': [1, 2, 3, 4]}
    438         self.assertEqual(ttk.tclobjs_to_py(adict), {'opt': [1, 2, 3, 4]})
    439 
    440         adict['opt'] = [1, 'xm', 3]
    441         self.assertEqual(ttk.tclobjs_to_py(adict), {'opt': [1, 'xm', 3]})
    442 
    443         adict['opt'] = (MockStateSpec('a', 'b'), u'vl')
    444         self.assertEqual(ttk.tclobjs_to_py(adict),
    445             {'opt': [('a', 'b', u'vl')]})
    446 
    447         self.assertEqual(ttk.tclobjs_to_py({'x': ['y z']}),
    448             {'x': ['y z']})
    449 
    450     def test_nosplit(self):
    451         self.assertEqual(ttk.tclobjs_to_py({'text': 'some text'}),
    452             {'text': 'some text'})
    453 
    454 tests_nogui = (InternalFunctionsTest, TclObjsToPyTest)
    455 
    456 if __name__ == "__main__":
    457     from test.test_support import run_unittest
    458     run_unittest(*tests_nogui)
    459