123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- #
- # BitBake Tests for Copy-on-Write (cow.py)
- #
- # SPDX-License-Identifier: GPL-2.0-only
- #
- # Copyright 2006 Holger Freyther <freyther@handhelds.org>
- # Copyright (C) 2020 Agilent Technologies, Inc.
- #
- import io
- import re
- import sys
- import unittest
- import contextlib
- import collections
- from bb.COW import COWDictBase, COWSetBase, COWDictMeta, COWSetMeta
- class COWTestCase(unittest.TestCase):
- """
- Test case for the COW module from mithro
- """
- def setUp(self):
- self._track_warnings = False
- self._warning_file = io.StringIO()
- self._unhandled_warnings = collections.deque()
- COWDictBase.__warn__ = self._warning_file
- def tearDown(self):
- COWDictBase.__warn__ = sys.stderr
- if self._track_warnings:
- self._checkAllWarningsRead()
- def trackWarnings(self):
- self._track_warnings = True
- def _collectWarnings(self):
- self._warning_file.seek(0)
- for warning in self._warning_file:
- self._unhandled_warnings.append(warning.rstrip("\n"))
- self._warning_file.truncate(0)
- self._warning_file.seek(0)
- def _checkAllWarningsRead(self):
- self._collectWarnings()
- self.assertSequenceEqual(self._unhandled_warnings, [])
- @contextlib.contextmanager
- def checkReportsWarning(self, expected_warning):
- self._checkAllWarningsRead()
- yield
- self._collectWarnings()
- warning = self._unhandled_warnings.popleft()
- self.assertEqual(warning, expected_warning)
- def checkStrOutput(self, obj, expected_levels, expected_keys):
- if obj.__class__ is COWDictMeta:
- expected_class_name = "COWDict"
- elif obj.__class__ is COWSetMeta:
- expected_class_name = "COWSet"
- else:
- self.fail("obj is of unknown type {0}".format(type(obj)))
- s = str(obj)
- regex = re.compile(r"<(\w+) Level: (\d+) Current Keys: (\d+)>")
- match = regex.match(s)
- self.assertIsNotNone(match, "bad str output: '{0}'".format(s))
- class_name = match.group(1)
- self.assertEqual(class_name, expected_class_name)
- levels = int(match.group(2))
- self.assertEqual(levels, expected_levels, "wrong # levels in str: '{0}'".format(s))
- keys = int(match.group(3))
- self.assertEqual(keys, expected_keys, "wrong # keys in str: '{0}'".format(s))
- def testGetSet(self):
- """
- Test and set
- """
- a = COWDictBase.copy()
- self.assertEqual(False, 'a' in a)
- a['a'] = 'a'
- a['b'] = 'b'
- self.assertEqual(True, 'a' in a)
- self.assertEqual(True, 'b' in a)
- self.assertEqual('a', a['a'])
- self.assertEqual('b', a['b'])
- def testCopyCopy(self):
- """
- Test the copy of copies
- """
- # create two COW dict 'instances'
- b = COWDictBase.copy()
- c = COWDictBase.copy()
- # assign some keys to one instance, some keys to another
- b['a'] = 10
- b['c'] = 20
- c['a'] = 30
- # test separation of the two instances
- self.assertEqual(False, 'c' in c)
- self.assertEqual(30, c['a'])
- self.assertEqual(10, b['a'])
- # test copy
- b_2 = b.copy()
- c_2 = c.copy()
- self.assertEqual(False, 'c' in c_2)
- self.assertEqual(10, b_2['a'])
- b_2['d'] = 40
- self.assertEqual(False, 'd' in c_2)
- self.assertEqual(True, 'd' in b_2)
- self.assertEqual(40, b_2['d'])
- self.assertEqual(False, 'd' in b)
- self.assertEqual(False, 'd' in c)
- c_2['d'] = 30
- self.assertEqual(True, 'd' in c_2)
- self.assertEqual(True, 'd' in b_2)
- self.assertEqual(30, c_2['d'])
- self.assertEqual(40, b_2['d'])
- self.assertEqual(False, 'd' in b)
- self.assertEqual(False, 'd' in c)
- # test copy of the copy
- c_3 = c_2.copy()
- b_3 = b_2.copy()
- b_3_2 = b_2.copy()
- c_3['e'] = 4711
- self.assertEqual(4711, c_3['e'])
- self.assertEqual(False, 'e' in c_2)
- self.assertEqual(False, 'e' in b_3)
- self.assertEqual(False, 'e' in b_3_2)
- self.assertEqual(False, 'e' in b_2)
- b_3['e'] = 'viel'
- self.assertEqual('viel', b_3['e'])
- self.assertEqual(4711, c_3['e'])
- self.assertEqual(False, 'e' in c_2)
- self.assertEqual(True, 'e' in b_3)
- self.assertEqual(False, 'e' in b_3_2)
- self.assertEqual(False, 'e' in b_2)
- def testCow(self):
- self.trackWarnings()
- c = COWDictBase.copy()
- c['123'] = 1027
- c['other'] = 4711
- c['d'] = {'abc': 10, 'bcd': 20}
- copy = c.copy()
- self.assertEqual(1027, c['123'])
- self.assertEqual(4711, c['other'])
- self.assertEqual({'abc': 10, 'bcd': 20}, c['d'])
- self.assertEqual(1027, copy['123'])
- self.assertEqual(4711, copy['other'])
- with self.checkReportsWarning("Warning: Doing a copy because d is a mutable type."):
- self.assertEqual({'abc': 10, 'bcd': 20}, copy['d'])
- # cow it now
- copy['123'] = 1028
- copy['other'] = 4712
- copy['d']['abc'] = 20
- self.assertEqual(1027, c['123'])
- self.assertEqual(4711, c['other'])
- self.assertEqual({'abc': 10, 'bcd': 20}, c['d'])
- self.assertEqual(1028, copy['123'])
- self.assertEqual(4712, copy['other'])
- self.assertEqual({'abc': 20, 'bcd': 20}, copy['d'])
- def testOriginalTestSuite(self):
- # This test suite is a port of the original one from COW.py
- self.trackWarnings()
- a = COWDictBase.copy()
- self.checkStrOutput(a, 1, 0)
- a['a'] = 'a'
- a['b'] = 'b'
- a['dict'] = {}
- self.checkStrOutput(a, 1, 4) # 4th member is dict__mutable__
- b = a.copy()
- self.checkStrOutput(b, 2, 0)
- b['c'] = 'b'
- self.checkStrOutput(b, 2, 1)
- with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
- self.assertListEqual(list(a.iteritems()),
- [('a', 'a'),
- ('b', 'b'),
- ('dict', {})
- ])
- with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
- b_gen = b.iteritems()
- self.assertTupleEqual(next(b_gen), ('a', 'a'))
- self.assertTupleEqual(next(b_gen), ('b', 'b'))
- self.assertTupleEqual(next(b_gen), ('c', 'b'))
- with self.checkReportsWarning("Warning: Doing a copy because dict is a mutable type."):
- self.assertTupleEqual(next(b_gen), ('dict', {}))
- with self.assertRaises(StopIteration):
- next(b_gen)
- b['dict']['a'] = 'b'
- b['a'] = 'c'
- self.checkStrOutput(a, 1, 4)
- self.checkStrOutput(b, 2, 3)
- with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
- self.assertListEqual(list(a.iteritems()),
- [('a', 'a'),
- ('b', 'b'),
- ('dict', {})
- ])
- with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
- b_gen = b.iteritems()
- self.assertTupleEqual(next(b_gen), ('a', 'c'))
- self.assertTupleEqual(next(b_gen), ('b', 'b'))
- self.assertTupleEqual(next(b_gen), ('c', 'b'))
- self.assertTupleEqual(next(b_gen), ('dict', {'a': 'b'}))
- with self.assertRaises(StopIteration):
- next(b_gen)
- with self.assertRaises(KeyError):
- print(b["dict2"])
- a['set'] = COWSetBase()
- a['set'].add("o1")
- a['set'].add("o1")
- a['set'].add("o2")
- self.assertSetEqual(set(a['set'].itervalues()), {"o1", "o2"})
- self.assertSetEqual(set(b['set'].itervalues()), {"o1", "o2"})
- b['set'].add('o3')
- self.assertSetEqual(set(a['set'].itervalues()), {"o1", "o2"})
- self.assertSetEqual(set(b['set'].itervalues()), {"o1", "o2", "o3"})
- a['set2'] = set()
- a['set2'].add("o1")
- a['set2'].add("o1")
- a['set2'].add("o2")
- # We don't expect 'a' to change anymore
- def check_a():
- with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
- a_gen = a.iteritems()
- self.assertTupleEqual(next(a_gen), ('a', 'a'))
- self.assertTupleEqual(next(a_gen), ('b', 'b'))
- self.assertTupleEqual(next(a_gen), ('dict', {}))
- self.assertTupleEqual(next(a_gen), ('set2', {'o1', 'o2'}))
- a_sub_set = next(a_gen)
- self.assertEqual(a_sub_set[0], 'set')
- self.checkStrOutput(a_sub_set[1], 1, 2)
- self.assertSetEqual(set(a_sub_set[1].itervalues()), {'o1', 'o2'})
- check_a()
- b_gen = b.iteritems(readonly=True)
- self.assertTupleEqual(next(b_gen), ('a', 'c'))
- self.assertTupleEqual(next(b_gen), ('b', 'b'))
- self.assertTupleEqual(next(b_gen), ('c', 'b'))
- self.assertTupleEqual(next(b_gen), ('dict', {'a': 'b'}))
- self.assertTupleEqual(next(b_gen), ('set2', {'o1', 'o2'}))
- b_sub_set = next(b_gen)
- self.assertEqual(b_sub_set[0], 'set')
- self.checkStrOutput(b_sub_set[1], 2, 1)
- self.assertSetEqual(set(b_sub_set[1].itervalues()), {'o1', 'o2', 'o3'})
- del b['b']
- with self.assertRaises(KeyError):
- print(b['b'])
- self.assertFalse('b' in b)
- check_a()
- b.__revertitem__('b')
- check_a()
- self.assertEqual(b['b'], 'b')
- self.assertTrue('b' in b)
- b.__revertitem__('dict')
- check_a()
- b_gen = b.iteritems(readonly=True)
- self.assertTupleEqual(next(b_gen), ('a', 'c'))
- self.assertTupleEqual(next(b_gen), ('b', 'b'))
- self.assertTupleEqual(next(b_gen), ('c', 'b'))
- self.assertTupleEqual(next(b_gen), ('dict', {}))
- self.assertTupleEqual(next(b_gen), ('set2', {'o1', 'o2'}))
- b_sub_set = next(b_gen)
- self.assertEqual(b_sub_set[0], 'set')
- self.checkStrOutput(b_sub_set[1], 2, 1)
- self.assertSetEqual(set(b_sub_set[1].itervalues()), {'o1', 'o2', 'o3'})
- self.checkStrOutput(a, 1, 6)
- self.checkStrOutput(b, 2, 3)
- def testSetMethods(self):
- s = COWSetBase()
- with self.assertRaises(TypeError):
- print(s.iteritems())
- with self.assertRaises(TypeError):
- print(s.iterkeys())
|