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