1  import unittest
       2  import sys
       3  from collections import OrderedDict, UserDict
       4  from types import MappingProxyType
       5  from test import support
       6  from test.support import import_helper
       7  import _testcapi
       8  
       9  
      10  NULL = None
      11  
      12  class ESC[4;38;5;81mDictSubclass(ESC[4;38;5;149mdict):
      13      def __getitem__(self, key):
      14          raise RuntimeError('do not get evil')
      15      def __setitem__(self, key, value):
      16          raise RuntimeError('do not set evil')
      17      def __delitem__(self, key):
      18          raise RuntimeError('do not del evil')
      19  
      20  def gen():
      21      yield 'a'
      22      yield 'b'
      23      yield 'c'
      24  
      25  
      26  class ESC[4;38;5;81mCAPITest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      27  
      28      def test_dict_check(self):
      29          check = _testcapi.dict_check
      30          self.assertTrue(check({1: 2}))
      31          self.assertTrue(check(OrderedDict({1: 2})))
      32          self.assertFalse(check(UserDict({1: 2})))
      33          self.assertFalse(check([1, 2]))
      34          self.assertFalse(check(object()))
      35          #self.assertFalse(check(NULL))
      36  
      37      def test_dict_checkexact(self):
      38          check = _testcapi.dict_checkexact
      39          self.assertTrue(check({1: 2}))
      40          self.assertFalse(check(OrderedDict({1: 2})))
      41          self.assertFalse(check(UserDict({1: 2})))
      42          self.assertFalse(check([1, 2]))
      43          self.assertFalse(check(object()))
      44          #self.assertFalse(check(NULL))
      45  
      46      def test_dict_new(self):
      47          dict_new = _testcapi.dict_new
      48          dct = dict_new()
      49          self.assertEqual(dct, {})
      50          self.assertIs(type(dct), dict)
      51          dct2 = dict_new()
      52          self.assertIsNot(dct2, dct)
      53  
      54      def test_dictproxy_new(self):
      55          dictproxy_new = _testcapi.dictproxy_new
      56          for dct in {1: 2}, OrderedDict({1: 2}), UserDict({1: 2}):
      57              proxy = dictproxy_new(dct)
      58              self.assertIs(type(proxy), MappingProxyType)
      59              self.assertEqual(proxy, dct)
      60              with self.assertRaises(TypeError):
      61                  proxy[1] = 3
      62              self.assertEqual(proxy[1], 2)
      63              dct[1] = 4
      64              self.assertEqual(proxy[1], 4)
      65  
      66          self.assertRaises(TypeError, dictproxy_new, [])
      67          self.assertRaises(TypeError, dictproxy_new, 42)
      68          # CRASHES dictproxy_new(NULL)
      69  
      70      def test_dict_copy(self):
      71          copy = _testcapi.dict_copy
      72          for dct in {1: 2}, OrderedDict({1: 2}):
      73              dct_copy = copy(dct)
      74              self.assertIs(type(dct_copy), dict)
      75              self.assertEqual(dct_copy, dct)
      76  
      77          self.assertRaises(SystemError, copy, UserDict())
      78          self.assertRaises(SystemError, copy, [])
      79          self.assertRaises(SystemError, copy, 42)
      80          self.assertRaises(SystemError, copy, NULL)
      81  
      82      def test_dict_clear(self):
      83          clear = _testcapi.dict_clear
      84          dct = {1: 2}
      85          clear(dct)
      86          self.assertEqual(dct, {})
      87  
      88          # NOTE: It is not safe to call it with OrderedDict.
      89  
      90          # Has no effect for non-dicts.
      91          dct = UserDict({1: 2})
      92          clear(dct)
      93          self.assertEqual(dct, {1: 2})
      94          lst = [1, 2]
      95          clear(lst)
      96          self.assertEqual(lst, [1, 2])
      97          clear(object())
      98  
      99          # CRASHES? clear(NULL)
     100  
     101      def test_dict_size(self):
     102          size = _testcapi.dict_size
     103          self.assertEqual(size({1: 2}), 1)
     104          self.assertEqual(size(OrderedDict({1: 2})), 1)
     105  
     106          self.assertRaises(SystemError, size, UserDict())
     107          self.assertRaises(SystemError, size, [])
     108          self.assertRaises(SystemError, size, 42)
     109          self.assertRaises(SystemError, size, object())
     110          self.assertRaises(SystemError, size, NULL)
     111  
     112      def test_dict_getitem(self):
     113          getitem = _testcapi.dict_getitem
     114          dct = {'a': 1, '\U0001f40d': 2}
     115          self.assertEqual(getitem(dct, 'a'), 1)
     116          self.assertIs(getitem(dct, 'b'), KeyError)
     117          self.assertEqual(getitem(dct, '\U0001f40d'), 2)
     118  
     119          dct2 = DictSubclass(dct)
     120          self.assertEqual(getitem(dct2, 'a'), 1)
     121          self.assertIs(getitem(dct2, 'b'), KeyError)
     122  
     123          self.assertIs(getitem({}, []), KeyError)  # unhashable
     124          self.assertIs(getitem(42, 'a'), KeyError)
     125          self.assertIs(getitem([1], 0), KeyError)
     126          # CRASHES getitem({}, NULL)
     127          # CRASHES getitem(NULL, 'a')
     128  
     129      def test_dict_getitemstring(self):
     130          getitemstring = _testcapi.dict_getitemstring
     131          dct = {'a': 1, '\U0001f40d': 2}
     132          self.assertEqual(getitemstring(dct, b'a'), 1)
     133          self.assertIs(getitemstring(dct, b'b'), KeyError)
     134          self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2)
     135  
     136          dct2 = DictSubclass(dct)
     137          self.assertEqual(getitemstring(dct2, b'a'), 1)
     138          self.assertIs(getitemstring(dct2, b'b'), KeyError)
     139  
     140          self.assertIs(getitemstring({}, b'\xff'), KeyError)
     141          self.assertIs(getitemstring(42, b'a'), KeyError)
     142          self.assertIs(getitemstring([], b'a'), KeyError)
     143          # CRASHES getitemstring({}, NULL)
     144          # CRASHES getitemstring(NULL, b'a')
     145  
     146      def test_dict_getitemwitherror(self):
     147          getitem = _testcapi.dict_getitemwitherror
     148          dct = {'a': 1, '\U0001f40d': 2}
     149          self.assertEqual(getitem(dct, 'a'), 1)
     150          self.assertIs(getitem(dct, 'b'), KeyError)
     151          self.assertEqual(getitem(dct, '\U0001f40d'), 2)
     152  
     153          dct2 = DictSubclass(dct)
     154          self.assertEqual(getitem(dct2, 'a'), 1)
     155          self.assertIs(getitem(dct2, 'b'), KeyError)
     156  
     157          self.assertRaises(SystemError, getitem, 42, 'a')
     158          self.assertRaises(TypeError, getitem, {}, [])  # unhashable
     159          self.assertRaises(SystemError, getitem, [], 1)
     160          self.assertRaises(SystemError, getitem, [], 'a')
     161          # CRASHES getitem({}, NULL)
     162          # CRASHES getitem(NULL, 'a')
     163  
     164      def test_dict_contains(self):
     165          contains = _testcapi.dict_contains
     166          dct = {'a': 1, '\U0001f40d': 2}
     167          self.assertTrue(contains(dct, 'a'))
     168          self.assertFalse(contains(dct, 'b'))
     169          self.assertTrue(contains(dct, '\U0001f40d'))
     170  
     171          dct2 = DictSubclass(dct)
     172          self.assertTrue(contains(dct2, 'a'))
     173          self.assertFalse(contains(dct2, 'b'))
     174  
     175          self.assertRaises(TypeError, contains, {}, [])  # unhashable
     176          # CRASHES contains({}, NULL)
     177          # CRASHES contains(UserDict(), 'a')
     178          # CRASHES contains(42, 'a')
     179          # CRASHES contains(NULL, 'a')
     180  
     181      def test_dict_setitem(self):
     182          setitem = _testcapi.dict_setitem
     183          dct = {}
     184          setitem(dct, 'a', 5)
     185          self.assertEqual(dct, {'a': 5})
     186          setitem(dct, '\U0001f40d', 8)
     187          self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
     188  
     189          dct2 = DictSubclass()
     190          setitem(dct2, 'a', 5)
     191          self.assertEqual(dct2, {'a': 5})
     192  
     193          self.assertRaises(TypeError, setitem, {}, [], 5)  # unhashable
     194          self.assertRaises(SystemError, setitem, UserDict(), 'a', 5)
     195          self.assertRaises(SystemError, setitem, [1], 0, 5)
     196          self.assertRaises(SystemError, setitem, 42, 'a', 5)
     197          # CRASHES setitem({}, NULL, 5)
     198          # CRASHES setitem({}, 'a', NULL)
     199          # CRASHES setitem(NULL, 'a', 5)
     200  
     201      def test_dict_setitemstring(self):
     202          setitemstring = _testcapi.dict_setitemstring
     203          dct = {}
     204          setitemstring(dct, b'a', 5)
     205          self.assertEqual(dct, {'a': 5})
     206          setitemstring(dct, '\U0001f40d'.encode(), 8)
     207          self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
     208  
     209          dct2 = DictSubclass()
     210          setitemstring(dct2, b'a', 5)
     211          self.assertEqual(dct2, {'a': 5})
     212  
     213          self.assertRaises(UnicodeDecodeError, setitemstring, {}, b'\xff', 5)
     214          self.assertRaises(SystemError, setitemstring, UserDict(), b'a', 5)
     215          self.assertRaises(SystemError, setitemstring, 42, b'a', 5)
     216          # CRASHES setitemstring({}, NULL, 5)
     217          # CRASHES setitemstring({}, b'a', NULL)
     218          # CRASHES setitemstring(NULL, b'a', 5)
     219  
     220      def test_dict_delitem(self):
     221          delitem = _testcapi.dict_delitem
     222          dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
     223          delitem(dct, 'a')
     224          self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
     225          self.assertRaises(KeyError, delitem, dct, 'b')
     226          delitem(dct, '\U0001f40d')
     227          self.assertEqual(dct, {'c': 2})
     228  
     229          dct2 = DictSubclass({'a': 1, 'c': 2})
     230          delitem(dct2, 'a')
     231          self.assertEqual(dct2, {'c': 2})
     232          self.assertRaises(KeyError, delitem, dct2, 'b')
     233  
     234          self.assertRaises(TypeError, delitem, {}, [])  # unhashable
     235          self.assertRaises(SystemError, delitem, UserDict({'a': 1}), 'a')
     236          self.assertRaises(SystemError, delitem, [1], 0)
     237          self.assertRaises(SystemError, delitem, 42, 'a')
     238          # CRASHES delitem({}, NULL)
     239          # CRASHES delitem(NULL, 'a')
     240  
     241      def test_dict_delitemstring(self):
     242          delitemstring = _testcapi.dict_delitemstring
     243          dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
     244          delitemstring(dct, b'a')
     245          self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
     246          self.assertRaises(KeyError, delitemstring, dct, b'b')
     247          delitemstring(dct, '\U0001f40d'.encode())
     248          self.assertEqual(dct, {'c': 2})
     249  
     250          dct2 = DictSubclass({'a': 1, 'c': 2})
     251          delitemstring(dct2, b'a')
     252          self.assertEqual(dct2, {'c': 2})
     253          self.assertRaises(KeyError, delitemstring, dct2, b'b')
     254  
     255          self.assertRaises(UnicodeDecodeError, delitemstring, {}, b'\xff')
     256          self.assertRaises(SystemError, delitemstring, UserDict({'a': 1}), b'a')
     257          self.assertRaises(SystemError, delitemstring, 42, b'a')
     258          # CRASHES delitemstring({}, NULL)
     259          # CRASHES delitemstring(NULL, b'a')
     260  
     261      def test_dict_setdefault(self):
     262          setdefault = _testcapi.dict_setdefault
     263          dct = {}
     264          self.assertEqual(setdefault(dct, 'a', 5), 5)
     265          self.assertEqual(dct, {'a': 5})
     266          self.assertEqual(setdefault(dct, 'a', 8), 5)
     267          self.assertEqual(dct, {'a': 5})
     268  
     269          dct2 = DictSubclass()
     270          self.assertEqual(setdefault(dct2, 'a', 5), 5)
     271          self.assertEqual(dct2, {'a': 5})
     272          self.assertEqual(setdefault(dct2, 'a', 8), 5)
     273          self.assertEqual(dct2, {'a': 5})
     274  
     275          self.assertRaises(TypeError, setdefault, {}, [], 5)  # unhashable
     276          self.assertRaises(SystemError, setdefault, UserDict(), 'a', 5)
     277          self.assertRaises(SystemError, setdefault, [1], 0, 5)
     278          self.assertRaises(SystemError, setdefault, 42, 'a', 5)
     279          # CRASHES setdefault({}, NULL, 5)
     280          # CRASHES setdefault({}, 'a', NULL)
     281          # CRASHES setdefault(NULL, 'a', 5)
     282  
     283      def test_mapping_keys_valuesitems(self):
     284          class ESC[4;38;5;81mBadMapping(ESC[4;38;5;149mdict):
     285              def keys(self):
     286                  return None
     287              def values(self):
     288                  return None
     289              def items(self):
     290                  return None
     291          dict_obj = {'foo': 1, 'bar': 2, 'spam': 3}
     292          for mapping in [dict_obj, DictSubclass(dict_obj), BadMapping(dict_obj)]:
     293              self.assertListEqual(_testcapi.dict_keys(mapping),
     294                                   list(dict_obj.keys()))
     295              self.assertListEqual(_testcapi.dict_values(mapping),
     296                                   list(dict_obj.values()))
     297              self.assertListEqual(_testcapi.dict_items(mapping),
     298                                   list(dict_obj.items()))
     299  
     300      def test_dict_keys_valuesitems_bad_arg(self):
     301          for mapping in UserDict(), [], object():
     302              self.assertRaises(SystemError, _testcapi.dict_keys, mapping)
     303              self.assertRaises(SystemError, _testcapi.dict_values, mapping)
     304              self.assertRaises(SystemError, _testcapi.dict_items, mapping)
     305  
     306      def test_dict_next(self):
     307          dict_next = _testcapi.dict_next
     308          self.assertIsNone(dict_next({}, 0))
     309          dct = {'a': 1, 'b': 2, 'c': 3}
     310          pos = 0
     311          pairs = []
     312          while True:
     313              res = dict_next(dct, pos)
     314              if res is None:
     315                  break
     316              rc, pos, key, value = res
     317              self.assertEqual(rc, 1)
     318              pairs.append((key, value))
     319          self.assertEqual(pairs, list(dct.items()))
     320  
     321          # CRASHES dict_next(NULL, 0)
     322  
     323      def test_dict_update(self):
     324          update = _testcapi.dict_update
     325          for cls1 in dict, DictSubclass:
     326              for cls2 in dict, DictSubclass, UserDict:
     327                  dct = cls1({'a': 1, 'b': 2})
     328                  update(dct, cls2({'b': 3, 'c': 4}))
     329                  self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4})
     330  
     331          self.assertRaises(AttributeError, update, {}, [])
     332          self.assertRaises(AttributeError, update, {}, 42)
     333          self.assertRaises(SystemError, update, UserDict(), {})
     334          self.assertRaises(SystemError, update, 42, {})
     335          self.assertRaises(SystemError, update, {}, NULL)
     336          self.assertRaises(SystemError, update, NULL, {})
     337  
     338      def test_dict_merge(self):
     339          merge = _testcapi.dict_merge
     340          for cls1 in dict, DictSubclass:
     341              for cls2 in dict, DictSubclass, UserDict:
     342                  dct = cls1({'a': 1, 'b': 2})
     343                  merge(dct, cls2({'b': 3, 'c': 4}), 0)
     344                  self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4})
     345                  dct = cls1({'a': 1, 'b': 2})
     346                  merge(dct, cls2({'b': 3, 'c': 4}), 1)
     347                  self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4})
     348  
     349          self.assertRaises(AttributeError, merge, {}, [], 0)
     350          self.assertRaises(AttributeError, merge, {}, 42, 0)
     351          self.assertRaises(SystemError, merge, UserDict(), {}, 0)
     352          self.assertRaises(SystemError, merge, 42, {}, 0)
     353          self.assertRaises(SystemError, merge, {}, NULL, 0)
     354          self.assertRaises(SystemError, merge, NULL, {}, 0)
     355  
     356      def test_dict_mergefromseq2(self):
     357          mergefromseq2 = _testcapi.dict_mergefromseq2
     358          for cls1 in dict, DictSubclass:
     359              for cls2 in list, iter:
     360                  dct = cls1({'a': 1, 'b': 2})
     361                  mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 0)
     362                  self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4})
     363                  dct = cls1({'a': 1, 'b': 2})
     364                  mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 1)
     365                  self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4})
     366  
     367          self.assertRaises(ValueError, mergefromseq2, {}, [(1,)], 0)
     368          self.assertRaises(ValueError, mergefromseq2, {}, [(1, 2, 3)], 0)
     369          self.assertRaises(TypeError, mergefromseq2, {}, [1], 0)
     370          self.assertRaises(TypeError, mergefromseq2, {}, 42, 0)
     371          # CRASHES mergefromseq2(UserDict(), [], 0)
     372          # CRASHES mergefromseq2(42, [], 0)
     373          # CRASHES mergefromseq2({}, NULL, 0)
     374          # CRASHES mergefromseq2(NULL, {}, 0)
     375  
     376  
     377  if __name__ == "__main__":
     378      unittest.main()