xref: /openbmc/openbmc/poky/bitbake/lib/bb/tests/data.py (revision 517393d9)
1#
2# BitBake Tests for the Data Store (data.py/data_smart.py)
3#
4# Copyright (C) 2010 Chris Larson
5# Copyright (C) 2012 Richard Purdie
6#
7# SPDX-License-Identifier: GPL-2.0-only
8#
9
10import unittest
11import bb
12import bb.data
13import bb.parse
14import logging
15import os
16
17class LogRecord():
18    def __enter__(self):
19        logs = []
20        class LogHandler(logging.Handler):
21            def emit(self, record):
22                logs.append(record)
23        logger = logging.getLogger("BitBake")
24        handler = LogHandler()
25        self.handler = handler
26        logger.addHandler(handler)
27        return logs
28    def __exit__(self, type, value, traceback):
29        logger = logging.getLogger("BitBake")
30        logger.removeHandler(self.handler)
31        return
32
33def logContains(item, logs):
34    for l in logs:
35        m = l.getMessage()
36        if item in m:
37            return True
38    return False
39
40class DataExpansions(unittest.TestCase):
41    def setUp(self):
42        self.d = bb.data.init()
43        self.d["foo"] = "value_of_foo"
44        self.d["bar"] = "value_of_bar"
45        self.d["value_of_foo"] = "value_of_'value_of_foo'"
46
47    def test_one_var(self):
48        val = self.d.expand("${foo}")
49        self.assertEqual(str(val), "value_of_foo")
50
51    def test_indirect_one_var(self):
52        val = self.d.expand("${${foo}}")
53        self.assertEqual(str(val), "value_of_'value_of_foo'")
54
55    def test_indirect_and_another(self):
56        val = self.d.expand("${${foo}} ${bar}")
57        self.assertEqual(str(val), "value_of_'value_of_foo' value_of_bar")
58
59    def test_python_snippet(self):
60        val = self.d.expand("${@5*12}")
61        self.assertEqual(str(val), "60")
62
63    def test_python_snippet_w_dict(self):
64        val = self.d.expand("${@{ 'green': 1, 'blue': 2 }['green']}")
65        self.assertEqual(str(val), "1")
66
67    def test_python_unexpanded_multi(self):
68        self.d.setVar("bar", "${unsetvar}")
69        val = self.d.expand("${@2*2},${foo},${@d.getVar('foo') + ' ${bar}'},${foo}")
70        self.assertEqual(str(val), "4,value_of_foo,${@d.getVar('foo') + ' ${unsetvar}'},value_of_foo")
71
72    def test_expand_in_python_snippet(self):
73        val = self.d.expand("${@'boo ' + '${foo}'}")
74        self.assertEqual(str(val), "boo value_of_foo")
75
76    def test_python_snippet_getvar(self):
77        val = self.d.expand("${@d.getVar('foo') + ' ${bar}'}")
78        self.assertEqual(str(val), "value_of_foo value_of_bar")
79
80    def test_python_unexpanded(self):
81        self.d.setVar("bar", "${unsetvar}")
82        val = self.d.expand("${@d.getVar('foo') + ' ${bar}'}")
83        self.assertEqual(str(val), "${@d.getVar('foo') + ' ${unsetvar}'}")
84
85    def test_python_snippet_syntax_error(self):
86        self.d.setVar("FOO", "${@foo = 5}")
87        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
88
89    def test_python_snippet_runtime_error(self):
90        self.d.setVar("FOO", "${@int('test')}")
91        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
92
93    def test_python_snippet_error_path(self):
94        self.d.setVar("FOO", "foo value ${BAR}")
95        self.d.setVar("BAR", "bar value ${@int('test')}")
96        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
97
98    def test_value_containing_value(self):
99        val = self.d.expand("${@d.getVar('foo') + ' ${bar}'}")
100        self.assertEqual(str(val), "value_of_foo value_of_bar")
101
102    def test_reference_undefined_var(self):
103        val = self.d.expand("${undefinedvar} meh")
104        self.assertEqual(str(val), "${undefinedvar} meh")
105
106    def test_double_reference(self):
107        self.d.setVar("BAR", "bar value")
108        self.d.setVar("FOO", "${BAR} foo ${BAR}")
109        val = self.d.getVar("FOO")
110        self.assertEqual(str(val), "bar value foo bar value")
111
112    def test_direct_recursion(self):
113        self.d.setVar("FOO", "${FOO}")
114        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
115
116    def test_indirect_recursion(self):
117        self.d.setVar("FOO", "${BAR}")
118        self.d.setVar("BAR", "${BAZ}")
119        self.d.setVar("BAZ", "${FOO}")
120        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
121
122    def test_recursion_exception(self):
123        self.d.setVar("FOO", "${BAR}")
124        self.d.setVar("BAR", "${${@'FOO'}}")
125        self.assertRaises(bb.data_smart.ExpansionError, self.d.getVar, "FOO", True)
126
127    def test_incomplete_varexp_single_quotes(self):
128        self.d.setVar("FOO", "sed -i -e 's:IP{:I${:g' $pc")
129        val = self.d.getVar("FOO")
130        self.assertEqual(str(val), "sed -i -e 's:IP{:I${:g' $pc")
131
132    def test_nonstring(self):
133        self.d.setVar("TEST", 5)
134        val = self.d.getVar("TEST")
135        self.assertEqual(str(val), "5")
136
137    def test_rename(self):
138        self.d.renameVar("foo", "newfoo")
139        self.assertEqual(self.d.getVar("newfoo", False), "value_of_foo")
140        self.assertEqual(self.d.getVar("foo", False), None)
141
142    def test_deletion(self):
143        self.d.delVar("foo")
144        self.assertEqual(self.d.getVar("foo", False), None)
145
146    def test_keys(self):
147        keys = list(self.d.keys())
148        self.assertCountEqual(keys, ['value_of_foo', 'foo', 'bar'])
149
150    def test_keys_deletion(self):
151        newd = bb.data.createCopy(self.d)
152        newd.delVar("bar")
153        keys = list(newd.keys())
154        self.assertCountEqual(keys, ['value_of_foo', 'foo'])
155
156class TestNestedExpansions(unittest.TestCase):
157    def setUp(self):
158        self.d = bb.data.init()
159        self.d["foo"] = "foo"
160        self.d["bar"] = "bar"
161        self.d["value_of_foobar"] = "187"
162
163    def test_refs(self):
164        val = self.d.expand("${value_of_${foo}${bar}}")
165        self.assertEqual(str(val), "187")
166
167    #def test_python_refs(self):
168    #    val = self.d.expand("${@${@3}**2 + ${@4}**2}")
169    #    self.assertEqual(str(val), "25")
170
171    def test_ref_in_python_ref(self):
172        val = self.d.expand("${@'${foo}' + 'bar'}")
173        self.assertEqual(str(val), "foobar")
174
175    def test_python_ref_in_ref(self):
176        val = self.d.expand("${${@'f'+'o'+'o'}}")
177        self.assertEqual(str(val), "foo")
178
179    def test_deep_nesting(self):
180        depth = 100
181        val = self.d.expand("${" * depth + "foo" + "}" * depth)
182        self.assertEqual(str(val), "foo")
183
184    #def test_deep_python_nesting(self):
185    #    depth = 50
186    #    val = self.d.expand("${@" * depth + "1" + "+1}" * depth)
187    #    self.assertEqual(str(val), str(depth + 1))
188
189    def test_mixed(self):
190        val = self.d.expand("${value_of_${@('${foo}'+'bar')[0:3]}${${@'BAR'.lower()}}}")
191        self.assertEqual(str(val), "187")
192
193    def test_runtime(self):
194        val = self.d.expand("${${@'value_of' + '_f'+'o'+'o'+'b'+'a'+'r'}}")
195        self.assertEqual(str(val), "187")
196
197class TestMemoize(unittest.TestCase):
198    def test_memoized(self):
199        d = bb.data.init()
200        d.setVar("FOO", "bar")
201        self.assertTrue(d.getVar("FOO", False) is d.getVar("FOO", False))
202
203    def test_not_memoized(self):
204        d1 = bb.data.init()
205        d2 = bb.data.init()
206        d1.setVar("FOO", "bar")
207        d2.setVar("FOO", "bar2")
208        self.assertTrue(d1.getVar("FOO", False) is not d2.getVar("FOO", False))
209
210    def test_changed_after_memoized(self):
211        d = bb.data.init()
212        d.setVar("foo", "value of foo")
213        self.assertEqual(str(d.getVar("foo", False)), "value of foo")
214        d.setVar("foo", "second value of foo")
215        self.assertEqual(str(d.getVar("foo", False)), "second value of foo")
216
217    def test_same_value(self):
218        d = bb.data.init()
219        d.setVar("foo", "value of")
220        d.setVar("bar", "value of")
221        self.assertEqual(d.getVar("foo", False),
222                         d.getVar("bar", False))
223
224class TestConcat(unittest.TestCase):
225    def setUp(self):
226        self.d = bb.data.init()
227        self.d.setVar("FOO", "foo")
228        self.d.setVar("VAL", "val")
229        self.d.setVar("BAR", "bar")
230
231    def test_prepend(self):
232        self.d.setVar("TEST", "${VAL}")
233        self.d.prependVar("TEST", "${FOO}:")
234        self.assertEqual(self.d.getVar("TEST"), "foo:val")
235
236    def test_append(self):
237        self.d.setVar("TEST", "${VAL}")
238        self.d.appendVar("TEST", ":${BAR}")
239        self.assertEqual(self.d.getVar("TEST"), "val:bar")
240
241    def test_multiple_append(self):
242        self.d.setVar("TEST", "${VAL}")
243        self.d.prependVar("TEST", "${FOO}:")
244        self.d.appendVar("TEST", ":val2")
245        self.d.appendVar("TEST", ":${BAR}")
246        self.assertEqual(self.d.getVar("TEST"), "foo:val:val2:bar")
247
248class TestConcatOverride(unittest.TestCase):
249    def setUp(self):
250        self.d = bb.data.init()
251        self.d.setVar("FOO", "foo")
252        self.d.setVar("VAL", "val")
253        self.d.setVar("BAR", "bar")
254
255    def test_prepend(self):
256        self.d.setVar("TEST", "${VAL}")
257        self.d.setVar("TEST:prepend", "${FOO}:")
258        self.assertEqual(self.d.getVar("TEST"), "foo:val")
259
260    def test_append(self):
261        self.d.setVar("TEST", "${VAL}")
262        self.d.setVar("TEST:append", ":${BAR}")
263        self.assertEqual(self.d.getVar("TEST"), "val:bar")
264
265    def test_multiple_append(self):
266        self.d.setVar("TEST", "${VAL}")
267        self.d.setVar("TEST:prepend", "${FOO}:")
268        self.d.setVar("TEST:append", ":val2")
269        self.d.setVar("TEST:append", ":${BAR}")
270        self.assertEqual(self.d.getVar("TEST"), "foo:val:val2:bar")
271
272    def test_append_unset(self):
273        self.d.setVar("TEST:prepend", "${FOO}:")
274        self.d.setVar("TEST:append", ":val2")
275        self.d.setVar("TEST:append", ":${BAR}")
276        self.assertEqual(self.d.getVar("TEST"), "foo::val2:bar")
277
278    def test_remove(self):
279        self.d.setVar("TEST", "${VAL} ${BAR}")
280        self.d.setVar("TEST:remove", "val")
281        self.assertEqual(self.d.getVar("TEST"), " bar")
282
283    def test_remove_cleared(self):
284        self.d.setVar("TEST", "${VAL} ${BAR}")
285        self.d.setVar("TEST:remove", "val")
286        self.d.setVar("TEST", "${VAL} ${BAR}")
287        self.assertEqual(self.d.getVar("TEST"), "val bar")
288
289    # Ensure the value is unchanged if we have an inactive remove override
290    # (including that whitespace is preserved)
291    def test_remove_inactive_override(self):
292        self.d.setVar("TEST", "${VAL} ${BAR}    123")
293        self.d.setVar("TEST:remove:inactiveoverride", "val")
294        self.assertEqual(self.d.getVar("TEST"), "val bar    123")
295
296    def test_doubleref_remove(self):
297        self.d.setVar("TEST", "${VAL} ${BAR}")
298        self.d.setVar("TEST:remove", "val")
299        self.d.setVar("TEST_TEST", "${TEST} ${TEST}")
300        self.assertEqual(self.d.getVar("TEST_TEST"), " bar  bar")
301
302    def test_empty_remove(self):
303        self.d.setVar("TEST", "")
304        self.d.setVar("TEST:remove", "val")
305        self.assertEqual(self.d.getVar("TEST"), "")
306
307    def test_remove_expansion(self):
308        self.d.setVar("BAR", "Z")
309        self.d.setVar("TEST", "${BAR}/X Y")
310        self.d.setVar("TEST:remove", "${BAR}/X")
311        self.assertEqual(self.d.getVar("TEST"), " Y")
312
313    def test_remove_expansion_items(self):
314        self.d.setVar("TEST", "A B C D")
315        self.d.setVar("BAR", "B D")
316        self.d.setVar("TEST:remove", "${BAR}")
317        self.assertEqual(self.d.getVar("TEST"), "A  C ")
318
319    def test_remove_preserve_whitespace(self):
320        # When the removal isn't active, the original value should be preserved
321        self.d.setVar("TEST", " A B")
322        self.d.setVar("TEST:remove", "C")
323        self.assertEqual(self.d.getVar("TEST"), " A B")
324
325    def test_remove_preserve_whitespace2(self):
326        # When the removal is active preserve the whitespace
327        self.d.setVar("TEST", " A B")
328        self.d.setVar("TEST:remove", "B")
329        self.assertEqual(self.d.getVar("TEST"), " A ")
330
331class TestOverrides(unittest.TestCase):
332    def setUp(self):
333        self.d = bb.data.init()
334        self.d.setVar("OVERRIDES", "foo:bar:local")
335        self.d.setVar("TEST", "testvalue")
336
337    def test_no_override(self):
338        self.assertEqual(self.d.getVar("TEST"), "testvalue")
339
340    def test_one_override(self):
341        self.d.setVar("TEST:bar", "testvalue2")
342        self.assertEqual(self.d.getVar("TEST"), "testvalue2")
343
344    def test_one_override_unset(self):
345        self.d.setVar("TEST2:bar", "testvalue2")
346
347        self.assertEqual(self.d.getVar("TEST2"), "testvalue2")
348        self.assertCountEqual(list(self.d.keys()), ['TEST', 'TEST2', 'OVERRIDES', 'TEST2:bar'])
349
350    def test_multiple_override(self):
351        self.d.setVar("TEST:bar", "testvalue2")
352        self.d.setVar("TEST:local", "testvalue3")
353        self.d.setVar("TEST:foo", "testvalue4")
354        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
355        self.assertCountEqual(list(self.d.keys()), ['TEST', 'TEST:foo', 'OVERRIDES', 'TEST:bar', 'TEST:local'])
356
357    def test_multiple_combined_overrides(self):
358        self.d.setVar("TEST:local:foo:bar", "testvalue3")
359        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
360
361    def test_multiple_overrides_unset(self):
362        self.d.setVar("TEST2:local:foo:bar", "testvalue3")
363        self.assertEqual(self.d.getVar("TEST2"), "testvalue3")
364
365    def test_keyexpansion_override(self):
366        self.d.setVar("LOCAL", "local")
367        self.d.setVar("TEST:bar", "testvalue2")
368        self.d.setVar("TEST:${LOCAL}", "testvalue3")
369        self.d.setVar("TEST:foo", "testvalue4")
370        bb.data.expandKeys(self.d)
371        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
372
373    def test_rename_override(self):
374        self.d.setVar("ALTERNATIVE:ncurses-tools:class-target", "a")
375        self.d.setVar("OVERRIDES", "class-target")
376        self.d.renameVar("ALTERNATIVE:ncurses-tools", "ALTERNATIVE:lib32-ncurses-tools")
377        self.assertEqual(self.d.getVar("ALTERNATIVE:lib32-ncurses-tools"), "a")
378
379    def test_underscore_override(self):
380        self.d.setVar("TEST:bar", "testvalue2")
381        self.d.setVar("TEST:some_val", "testvalue3")
382        self.d.setVar("TEST:foo", "testvalue4")
383        self.d.setVar("OVERRIDES", "foo:bar:some_val")
384        self.assertEqual(self.d.getVar("TEST"), "testvalue3")
385
386    def test_remove_with_override(self):
387        self.d.setVar("TEST:bar", "testvalue2")
388        self.d.setVar("TEST:some_val", "testvalue3 testvalue5")
389        self.d.setVar("TEST:some_val:remove", "testvalue3")
390        self.d.setVar("TEST:foo", "testvalue4")
391        self.d.setVar("OVERRIDES", "foo:bar:some_val")
392        self.assertEqual(self.d.getVar("TEST"), " testvalue5")
393
394    def test_append_and_override_1(self):
395        self.d.setVar("TEST:append", "testvalue2")
396        self.d.setVar("TEST:bar", "testvalue3")
397        self.assertEqual(self.d.getVar("TEST"), "testvalue3testvalue2")
398
399    def test_append_and_override_2(self):
400        self.d.setVar("TEST:append:bar", "testvalue2")
401        self.assertEqual(self.d.getVar("TEST"), "testvaluetestvalue2")
402
403    def test_append_and_override_3(self):
404        self.d.setVar("TEST:bar:append", "testvalue2")
405        self.assertEqual(self.d.getVar("TEST"), "testvalue2")
406
407    # Test an override with _<numeric> in it based on a real world OE issue
408    def test_underscore_override(self):
409        self.d.setVar("TARGET_ARCH", "x86_64")
410        self.d.setVar("PN", "test-${TARGET_ARCH}")
411        self.d.setVar("VERSION", "1")
412        self.d.setVar("VERSION:pn-test-${TARGET_ARCH}", "2")
413        self.d.setVar("OVERRIDES", "pn-${PN}")
414        bb.data.expandKeys(self.d)
415        self.assertEqual(self.d.getVar("VERSION"), "2")
416
417    def test_append_and_unused_override(self):
418        # Had a bug where an unused override append could return "" instead of None
419        self.d.setVar("BAR:append:unusedoverride", "testvalue2")
420        self.assertEqual(self.d.getVar("BAR"), None)
421
422class TestKeyExpansion(unittest.TestCase):
423    def setUp(self):
424        self.d = bb.data.init()
425        self.d.setVar("FOO", "foo")
426        self.d.setVar("BAR", "foo")
427
428    def test_keyexpand(self):
429        self.d.setVar("VAL_${FOO}", "A")
430        self.d.setVar("VAL_${BAR}", "B")
431        with LogRecord() as logs:
432            bb.data.expandKeys(self.d)
433            self.assertTrue(logContains("Variable key VAL_${FOO} (A) replaces original key VAL_foo (B)", logs))
434        self.assertEqual(self.d.getVar("VAL_foo"), "A")
435
436class TestFlags(unittest.TestCase):
437    def setUp(self):
438        self.d = bb.data.init()
439        self.d.setVar("foo", "value of foo")
440        self.d.setVarFlag("foo", "flag1", "value of flag1")
441        self.d.setVarFlag("foo", "flag2", "value of flag2")
442
443    def test_setflag(self):
444        self.assertEqual(self.d.getVarFlag("foo", "flag1", False), "value of flag1")
445        self.assertEqual(self.d.getVarFlag("foo", "flag2", False), "value of flag2")
446
447    def test_delflag(self):
448        self.d.delVarFlag("foo", "flag2")
449        self.assertEqual(self.d.getVarFlag("foo", "flag1", False), "value of flag1")
450        self.assertEqual(self.d.getVarFlag("foo", "flag2", False), None)
451
452
453class Contains(unittest.TestCase):
454    def setUp(self):
455        self.d = bb.data.init()
456        self.d.setVar("SOMEFLAG", "a b c")
457
458    def test_contains(self):
459        self.assertTrue(bb.utils.contains("SOMEFLAG", "a", True, False, self.d))
460        self.assertTrue(bb.utils.contains("SOMEFLAG", "b", True, False, self.d))
461        self.assertTrue(bb.utils.contains("SOMEFLAG", "c", True, False, self.d))
462
463        self.assertTrue(bb.utils.contains("SOMEFLAG", "a b", True, False, self.d))
464        self.assertTrue(bb.utils.contains("SOMEFLAG", "b c", True, False, self.d))
465        self.assertTrue(bb.utils.contains("SOMEFLAG", "c a", True, False, self.d))
466
467        self.assertTrue(bb.utils.contains("SOMEFLAG", "a b c", True, False, self.d))
468        self.assertTrue(bb.utils.contains("SOMEFLAG", "c b a", True, False, self.d))
469
470        self.assertFalse(bb.utils.contains("SOMEFLAG", "x", True, False, self.d))
471        self.assertFalse(bb.utils.contains("SOMEFLAG", "a x", True, False, self.d))
472        self.assertFalse(bb.utils.contains("SOMEFLAG", "x c b", True, False, self.d))
473        self.assertFalse(bb.utils.contains("SOMEFLAG", "x c b a", True, False, self.d))
474
475    def test_contains_any(self):
476        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "a", True, False, self.d))
477        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "b", True, False, self.d))
478        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "c", True, False, self.d))
479
480        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "a b", True, False, self.d))
481        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "b c", True, False, self.d))
482        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "c a", True, False, self.d))
483
484        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "a x", True, False, self.d))
485        self.assertTrue(bb.utils.contains_any("SOMEFLAG", "x c", True, False, self.d))
486
487        self.assertFalse(bb.utils.contains_any("SOMEFLAG", "x", True, False, self.d))
488        self.assertFalse(bb.utils.contains_any("SOMEFLAG", "x y z", True, False, self.d))
489
490
491class TaskHash(unittest.TestCase):
492    def test_taskhashes(self):
493        def gettask_bashhash(taskname, d):
494            tasklist, gendeps, lookupcache = bb.data.generate_dependencies(d, set())
495            taskdeps, basehash = bb.data.generate_dependency_hash(tasklist, gendeps, lookupcache, set(), "somefile")
496            bb.warn(str(lookupcache))
497            return basehash["somefile:" + taskname]
498
499        d = bb.data.init()
500        d.setVar("__BBTASKS", ["mytask"])
501        d.setVar("__exportlist", [])
502        d.setVar("mytask", "${MYCOMMAND}")
503        d.setVar("MYCOMMAND", "${VAR}; foo; bar; exit 0")
504        d.setVar("VAR", "val")
505        orighash = gettask_bashhash("mytask", d)
506
507        # Changing a variable should change the hash
508        d.setVar("VAR", "val2")
509        nexthash = gettask_bashhash("mytask", d)
510        self.assertNotEqual(orighash, nexthash)
511
512        d.setVar("VAR", "val")
513        # Adding an inactive removal shouldn't change the hash
514        d.setVar("BAR", "notbar")
515        d.setVar("MYCOMMAND:remove", "${BAR}")
516        nexthash = gettask_bashhash("mytask", d)
517        self.assertEqual(orighash, nexthash)
518
519        # Adding an active removal should change the hash
520        d.setVar("BAR", "bar;")
521        nexthash = gettask_bashhash("mytask", d)
522        self.assertNotEqual(orighash, nexthash)
523
524        # Setup an inactive contains()
525        d.setVar("VAR", "${@bb.utils.contains('VAR2', 'A', 'val', '', d)}")
526        orighash = gettask_bashhash("mytask", d)
527
528        # Activate the contains() and the hash should change
529        d.setVar("VAR2", "A")
530        nexthash = gettask_bashhash("mytask", d)
531        self.assertNotEqual(orighash, nexthash)
532
533        # The contains should be inactive but even though VAR2 has a
534        # different value the hash should match the original
535        d.setVar("VAR2", "B")
536        nexthash = gettask_bashhash("mytask", d)
537        self.assertEqual(orighash, nexthash)
538
539class Serialize(unittest.TestCase):
540
541    def test_serialize(self):
542        import tempfile
543        import pickle
544        d = bb.data.init()
545        d.enableTracking()
546        d.setVar('HELLO', 'world')
547        d.setVarFlag('HELLO', 'other', 'planet')
548        with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
549            tmpfilename = tmpfile.name
550            pickle.dump(d, tmpfile)
551
552        with open(tmpfilename, 'rb') as f:
553            newd = pickle.load(f)
554
555        os.remove(tmpfilename)
556
557        self.assertEqual(d, newd)
558        self.assertEqual(newd.getVar('HELLO'), 'world')
559        self.assertEqual(newd.getVarFlag('HELLO', 'other'), 'planet')
560
561
562