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