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