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