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