xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/tests/cow.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# BitBake Tests for Copy-on-Write (cow.py)
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
5*4882a593Smuzhiyun#
6*4882a593Smuzhiyun# Copyright 2006 Holger Freyther <freyther@handhelds.org>
7*4882a593Smuzhiyun# Copyright (C) 2020  Agilent Technologies, Inc.
8*4882a593Smuzhiyun#
9*4882a593Smuzhiyun
10*4882a593Smuzhiyunimport io
11*4882a593Smuzhiyunimport re
12*4882a593Smuzhiyunimport sys
13*4882a593Smuzhiyunimport unittest
14*4882a593Smuzhiyunimport contextlib
15*4882a593Smuzhiyunimport collections
16*4882a593Smuzhiyun
17*4882a593Smuzhiyunfrom bb.COW import COWDictBase, COWSetBase, COWDictMeta, COWSetMeta
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun
20*4882a593Smuzhiyunclass COWTestCase(unittest.TestCase):
21*4882a593Smuzhiyun    """
22*4882a593Smuzhiyun    Test case for the COW module from mithro
23*4882a593Smuzhiyun    """
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun    def setUp(self):
26*4882a593Smuzhiyun        self._track_warnings = False
27*4882a593Smuzhiyun        self._warning_file = io.StringIO()
28*4882a593Smuzhiyun        self._unhandled_warnings = collections.deque()
29*4882a593Smuzhiyun        COWDictBase.__warn__ = self._warning_file
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun    def tearDown(self):
32*4882a593Smuzhiyun        COWDictBase.__warn__ = sys.stderr
33*4882a593Smuzhiyun        if self._track_warnings:
34*4882a593Smuzhiyun            self._checkAllWarningsRead()
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun    def trackWarnings(self):
37*4882a593Smuzhiyun        self._track_warnings = True
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun    def _collectWarnings(self):
40*4882a593Smuzhiyun        self._warning_file.seek(0)
41*4882a593Smuzhiyun        for warning in self._warning_file:
42*4882a593Smuzhiyun            self._unhandled_warnings.append(warning.rstrip("\n"))
43*4882a593Smuzhiyun        self._warning_file.truncate(0)
44*4882a593Smuzhiyun        self._warning_file.seek(0)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun    def _checkAllWarningsRead(self):
47*4882a593Smuzhiyun        self._collectWarnings()
48*4882a593Smuzhiyun        self.assertSequenceEqual(self._unhandled_warnings, [])
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun    @contextlib.contextmanager
51*4882a593Smuzhiyun    def checkReportsWarning(self, expected_warning):
52*4882a593Smuzhiyun        self._checkAllWarningsRead()
53*4882a593Smuzhiyun        yield
54*4882a593Smuzhiyun        self._collectWarnings()
55*4882a593Smuzhiyun        warning = self._unhandled_warnings.popleft()
56*4882a593Smuzhiyun        self.assertEqual(warning, expected_warning)
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun    def checkStrOutput(self, obj, expected_levels, expected_keys):
59*4882a593Smuzhiyun        if obj.__class__ is COWDictMeta:
60*4882a593Smuzhiyun            expected_class_name = "COWDict"
61*4882a593Smuzhiyun        elif obj.__class__ is COWSetMeta:
62*4882a593Smuzhiyun            expected_class_name = "COWSet"
63*4882a593Smuzhiyun        else:
64*4882a593Smuzhiyun            self.fail("obj is of unknown type {0}".format(type(obj)))
65*4882a593Smuzhiyun        s = str(obj)
66*4882a593Smuzhiyun        regex = re.compile(r"<(\w+) Level: (\d+) Current Keys: (\d+)>")
67*4882a593Smuzhiyun        match = regex.match(s)
68*4882a593Smuzhiyun        self.assertIsNotNone(match, "bad str output: '{0}'".format(s))
69*4882a593Smuzhiyun        class_name = match.group(1)
70*4882a593Smuzhiyun        self.assertEqual(class_name, expected_class_name)
71*4882a593Smuzhiyun        levels = int(match.group(2))
72*4882a593Smuzhiyun        self.assertEqual(levels, expected_levels, "wrong # levels in str: '{0}'".format(s))
73*4882a593Smuzhiyun        keys = int(match.group(3))
74*4882a593Smuzhiyun        self.assertEqual(keys, expected_keys, "wrong # keys in str: '{0}'".format(s))
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun    def testGetSet(self):
77*4882a593Smuzhiyun        """
78*4882a593Smuzhiyun        Test and set
79*4882a593Smuzhiyun        """
80*4882a593Smuzhiyun        a = COWDictBase.copy()
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun        self.assertEqual(False, 'a' in a)
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun        a['a'] = 'a'
85*4882a593Smuzhiyun        a['b'] = 'b'
86*4882a593Smuzhiyun        self.assertEqual(True, 'a' in a)
87*4882a593Smuzhiyun        self.assertEqual(True, 'b' in a)
88*4882a593Smuzhiyun        self.assertEqual('a', a['a'])
89*4882a593Smuzhiyun        self.assertEqual('b', a['b'])
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun    def testCopyCopy(self):
92*4882a593Smuzhiyun        """
93*4882a593Smuzhiyun        Test the copy of copies
94*4882a593Smuzhiyun        """
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun        # create two COW dict 'instances'
97*4882a593Smuzhiyun        b = COWDictBase.copy()
98*4882a593Smuzhiyun        c = COWDictBase.copy()
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun        # assign some keys to one instance, some keys to another
101*4882a593Smuzhiyun        b['a'] = 10
102*4882a593Smuzhiyun        b['c'] = 20
103*4882a593Smuzhiyun        c['a'] = 30
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun        # test separation of the two instances
106*4882a593Smuzhiyun        self.assertEqual(False, 'c' in c)
107*4882a593Smuzhiyun        self.assertEqual(30, c['a'])
108*4882a593Smuzhiyun        self.assertEqual(10, b['a'])
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun        # test copy
111*4882a593Smuzhiyun        b_2 = b.copy()
112*4882a593Smuzhiyun        c_2 = c.copy()
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun        self.assertEqual(False, 'c' in c_2)
115*4882a593Smuzhiyun        self.assertEqual(10, b_2['a'])
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun        b_2['d'] = 40
118*4882a593Smuzhiyun        self.assertEqual(False, 'd' in c_2)
119*4882a593Smuzhiyun        self.assertEqual(True, 'd' in b_2)
120*4882a593Smuzhiyun        self.assertEqual(40, b_2['d'])
121*4882a593Smuzhiyun        self.assertEqual(False, 'd' in b)
122*4882a593Smuzhiyun        self.assertEqual(False, 'd' in c)
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun        c_2['d'] = 30
125*4882a593Smuzhiyun        self.assertEqual(True, 'd' in c_2)
126*4882a593Smuzhiyun        self.assertEqual(True, 'd' in b_2)
127*4882a593Smuzhiyun        self.assertEqual(30, c_2['d'])
128*4882a593Smuzhiyun        self.assertEqual(40, b_2['d'])
129*4882a593Smuzhiyun        self.assertEqual(False, 'd' in b)
130*4882a593Smuzhiyun        self.assertEqual(False, 'd' in c)
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun        # test copy of the copy
133*4882a593Smuzhiyun        c_3 = c_2.copy()
134*4882a593Smuzhiyun        b_3 = b_2.copy()
135*4882a593Smuzhiyun        b_3_2 = b_2.copy()
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun        c_3['e'] = 4711
138*4882a593Smuzhiyun        self.assertEqual(4711, c_3['e'])
139*4882a593Smuzhiyun        self.assertEqual(False, 'e' in c_2)
140*4882a593Smuzhiyun        self.assertEqual(False, 'e' in b_3)
141*4882a593Smuzhiyun        self.assertEqual(False, 'e' in b_3_2)
142*4882a593Smuzhiyun        self.assertEqual(False, 'e' in b_2)
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun        b_3['e'] = 'viel'
145*4882a593Smuzhiyun        self.assertEqual('viel', b_3['e'])
146*4882a593Smuzhiyun        self.assertEqual(4711, c_3['e'])
147*4882a593Smuzhiyun        self.assertEqual(False, 'e' in c_2)
148*4882a593Smuzhiyun        self.assertEqual(True, 'e' in b_3)
149*4882a593Smuzhiyun        self.assertEqual(False, 'e' in b_3_2)
150*4882a593Smuzhiyun        self.assertEqual(False, 'e' in b_2)
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun    def testCow(self):
153*4882a593Smuzhiyun        self.trackWarnings()
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun        c = COWDictBase.copy()
156*4882a593Smuzhiyun        c['123'] = 1027
157*4882a593Smuzhiyun        c['other'] = 4711
158*4882a593Smuzhiyun        c['d'] = {'abc': 10, 'bcd': 20}
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun        copy = c.copy()
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun        self.assertEqual(1027, c['123'])
163*4882a593Smuzhiyun        self.assertEqual(4711, c['other'])
164*4882a593Smuzhiyun        self.assertEqual({'abc': 10, 'bcd': 20}, c['d'])
165*4882a593Smuzhiyun        self.assertEqual(1027, copy['123'])
166*4882a593Smuzhiyun        self.assertEqual(4711, copy['other'])
167*4882a593Smuzhiyun        with self.checkReportsWarning("Warning: Doing a copy because d is a mutable type."):
168*4882a593Smuzhiyun            self.assertEqual({'abc': 10, 'bcd': 20}, copy['d'])
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun        # cow it now
171*4882a593Smuzhiyun        copy['123'] = 1028
172*4882a593Smuzhiyun        copy['other'] = 4712
173*4882a593Smuzhiyun        copy['d']['abc'] = 20
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun        self.assertEqual(1027, c['123'])
176*4882a593Smuzhiyun        self.assertEqual(4711, c['other'])
177*4882a593Smuzhiyun        self.assertEqual({'abc': 10, 'bcd': 20}, c['d'])
178*4882a593Smuzhiyun        self.assertEqual(1028, copy['123'])
179*4882a593Smuzhiyun        self.assertEqual(4712, copy['other'])
180*4882a593Smuzhiyun        self.assertEqual({'abc': 20, 'bcd': 20}, copy['d'])
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun    def testOriginalTestSuite(self):
183*4882a593Smuzhiyun        # This test suite is a port of the original one from COW.py
184*4882a593Smuzhiyun        self.trackWarnings()
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun        a = COWDictBase.copy()
187*4882a593Smuzhiyun        self.checkStrOutput(a, 1, 0)
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun        a['a'] = 'a'
190*4882a593Smuzhiyun        a['b'] = 'b'
191*4882a593Smuzhiyun        a['dict'] = {}
192*4882a593Smuzhiyun        self.checkStrOutput(a, 1, 4)  # 4th member is dict__mutable__
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun        b = a.copy()
195*4882a593Smuzhiyun        self.checkStrOutput(b, 2, 0)
196*4882a593Smuzhiyun        b['c'] = 'b'
197*4882a593Smuzhiyun        self.checkStrOutput(b, 2, 1)
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun        with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
200*4882a593Smuzhiyun            self.assertListEqual(list(a.iteritems()),
201*4882a593Smuzhiyun                                 [('a', 'a'),
202*4882a593Smuzhiyun                                  ('b', 'b'),
203*4882a593Smuzhiyun                                  ('dict', {})
204*4882a593Smuzhiyun                                  ])
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun        with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
207*4882a593Smuzhiyun            b_gen = b.iteritems()
208*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('a', 'a'))
209*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('b', 'b'))
210*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('c', 'b'))
211*4882a593Smuzhiyun        with self.checkReportsWarning("Warning: Doing a copy because dict is a mutable type."):
212*4882a593Smuzhiyun            self.assertTupleEqual(next(b_gen), ('dict', {}))
213*4882a593Smuzhiyun        with self.assertRaises(StopIteration):
214*4882a593Smuzhiyun            next(b_gen)
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun        b['dict']['a'] = 'b'
217*4882a593Smuzhiyun        b['a'] = 'c'
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun        self.checkStrOutput(a, 1, 4)
220*4882a593Smuzhiyun        self.checkStrOutput(b, 2, 3)
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun        with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
223*4882a593Smuzhiyun            self.assertListEqual(list(a.iteritems()),
224*4882a593Smuzhiyun                                 [('a', 'a'),
225*4882a593Smuzhiyun                                  ('b', 'b'),
226*4882a593Smuzhiyun                                  ('dict', {})
227*4882a593Smuzhiyun                                  ])
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun        with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
230*4882a593Smuzhiyun            b_gen = b.iteritems()
231*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('a', 'c'))
232*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('b', 'b'))
233*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('c', 'b'))
234*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('dict', {'a': 'b'}))
235*4882a593Smuzhiyun        with self.assertRaises(StopIteration):
236*4882a593Smuzhiyun            next(b_gen)
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun        with self.assertRaises(KeyError):
239*4882a593Smuzhiyun            print(b["dict2"])
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun        a['set'] = COWSetBase()
242*4882a593Smuzhiyun        a['set'].add("o1")
243*4882a593Smuzhiyun        a['set'].add("o1")
244*4882a593Smuzhiyun        a['set'].add("o2")
245*4882a593Smuzhiyun        self.assertSetEqual(set(a['set'].itervalues()), {"o1", "o2"})
246*4882a593Smuzhiyun        self.assertSetEqual(set(b['set'].itervalues()), {"o1", "o2"})
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun        b['set'].add('o3')
249*4882a593Smuzhiyun        self.assertSetEqual(set(a['set'].itervalues()), {"o1", "o2"})
250*4882a593Smuzhiyun        self.assertSetEqual(set(b['set'].itervalues()), {"o1", "o2", "o3"})
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun        a['set2'] = set()
253*4882a593Smuzhiyun        a['set2'].add("o1")
254*4882a593Smuzhiyun        a['set2'].add("o1")
255*4882a593Smuzhiyun        a['set2'].add("o2")
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun        # We don't expect 'a' to change anymore
258*4882a593Smuzhiyun        def check_a():
259*4882a593Smuzhiyun            with self.checkReportsWarning("Warning: If you aren't going to change any of the values call with True."):
260*4882a593Smuzhiyun                a_gen = a.iteritems()
261*4882a593Smuzhiyun                self.assertTupleEqual(next(a_gen), ('a', 'a'))
262*4882a593Smuzhiyun            self.assertTupleEqual(next(a_gen), ('b', 'b'))
263*4882a593Smuzhiyun            self.assertTupleEqual(next(a_gen), ('dict', {}))
264*4882a593Smuzhiyun            self.assertTupleEqual(next(a_gen), ('set2', {'o1', 'o2'}))
265*4882a593Smuzhiyun            a_sub_set = next(a_gen)
266*4882a593Smuzhiyun            self.assertEqual(a_sub_set[0], 'set')
267*4882a593Smuzhiyun            self.checkStrOutput(a_sub_set[1], 1, 2)
268*4882a593Smuzhiyun            self.assertSetEqual(set(a_sub_set[1].itervalues()), {'o1', 'o2'})
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun        check_a()
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun        b_gen = b.iteritems(readonly=True)
273*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('a', 'c'))
274*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('b', 'b'))
275*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('c', 'b'))
276*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('dict', {'a': 'b'}))
277*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('set2', {'o1', 'o2'}))
278*4882a593Smuzhiyun        b_sub_set = next(b_gen)
279*4882a593Smuzhiyun        self.assertEqual(b_sub_set[0], 'set')
280*4882a593Smuzhiyun        self.checkStrOutput(b_sub_set[1], 2, 1)
281*4882a593Smuzhiyun        self.assertSetEqual(set(b_sub_set[1].itervalues()), {'o1', 'o2', 'o3'})
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun        del b['b']
284*4882a593Smuzhiyun        with self.assertRaises(KeyError):
285*4882a593Smuzhiyun            print(b['b'])
286*4882a593Smuzhiyun        self.assertFalse('b' in b)
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun        check_a()
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun        b.__revertitem__('b')
291*4882a593Smuzhiyun        check_a()
292*4882a593Smuzhiyun        self.assertEqual(b['b'], 'b')
293*4882a593Smuzhiyun        self.assertTrue('b' in b)
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun        b.__revertitem__('dict')
296*4882a593Smuzhiyun        check_a()
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun        b_gen = b.iteritems(readonly=True)
299*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('a', 'c'))
300*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('b', 'b'))
301*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('c', 'b'))
302*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('dict', {}))
303*4882a593Smuzhiyun        self.assertTupleEqual(next(b_gen), ('set2', {'o1', 'o2'}))
304*4882a593Smuzhiyun        b_sub_set = next(b_gen)
305*4882a593Smuzhiyun        self.assertEqual(b_sub_set[0], 'set')
306*4882a593Smuzhiyun        self.checkStrOutput(b_sub_set[1], 2, 1)
307*4882a593Smuzhiyun        self.assertSetEqual(set(b_sub_set[1].itervalues()), {'o1', 'o2', 'o3'})
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun        self.checkStrOutput(a, 1, 6)
310*4882a593Smuzhiyun        self.checkStrOutput(b, 2, 3)
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun    def testSetMethods(self):
313*4882a593Smuzhiyun        s = COWSetBase()
314*4882a593Smuzhiyun        with self.assertRaises(TypeError):
315*4882a593Smuzhiyun            print(s.iteritems())
316*4882a593Smuzhiyun        with self.assertRaises(TypeError):
317*4882a593Smuzhiyun            print(s.iterkeys())
318