summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/tests/codeparser.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/tests/codeparser.py')
-rw-r--r--bitbake/lib/bb/tests/codeparser.py374
1 files changed, 374 insertions, 0 deletions
diff --git a/bitbake/lib/bb/tests/codeparser.py b/bitbake/lib/bb/tests/codeparser.py
new file mode 100644
index 0000000000..938b04b2c6
--- /dev/null
+++ b/bitbake/lib/bb/tests/codeparser.py
@@ -0,0 +1,374 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# BitBake Test for codeparser.py
5#
6# Copyright (C) 2010 Chris Larson
7# Copyright (C) 2012 Richard Purdie
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21#
22
23import unittest
24import logging
25import bb
26
27logger = logging.getLogger('BitBake.TestCodeParser')
28
29# bb.data references bb.parse but can't directly import due to circular dependencies.
30# Hack around it for now :(
31import bb.parse
32import bb.data
33
34class ReferenceTest(unittest.TestCase):
35 def setUp(self):
36 self.d = bb.data.init()
37
38 def setEmptyVars(self, varlist):
39 for k in varlist:
40 self.d.setVar(k, "")
41
42 def setValues(self, values):
43 for k, v in values.items():
44 self.d.setVar(k, v)
45
46 def assertReferences(self, refs):
47 self.assertEqual(self.references, refs)
48
49 def assertExecs(self, execs):
50 self.assertEqual(self.execs, execs)
51
52class VariableReferenceTest(ReferenceTest):
53
54 def parseExpression(self, exp):
55 parsedvar = self.d.expandWithRefs(exp, None)
56 self.references = parsedvar.references
57
58 def test_simple_reference(self):
59 self.setEmptyVars(["FOO"])
60 self.parseExpression("${FOO}")
61 self.assertReferences(set(["FOO"]))
62
63 def test_nested_reference(self):
64 self.setEmptyVars(["BAR"])
65 self.d.setVar("FOO", "BAR")
66 self.parseExpression("${${FOO}}")
67 self.assertReferences(set(["FOO", "BAR"]))
68
69 def test_python_reference(self):
70 self.setEmptyVars(["BAR"])
71 self.parseExpression("${@bb.data.getVar('BAR', d, True) + 'foo'}")
72 self.assertReferences(set(["BAR"]))
73
74class ShellReferenceTest(ReferenceTest):
75
76 def parseExpression(self, exp):
77 parsedvar = self.d.expandWithRefs(exp, None)
78 parser = bb.codeparser.ShellParser("ParserTest", logger)
79 parser.parse_shell(parsedvar.value)
80
81 self.references = parsedvar.references
82 self.execs = parser.execs
83
84 def test_quotes_inside_assign(self):
85 self.parseExpression('foo=foo"bar"baz')
86 self.assertReferences(set([]))
87
88 def test_quotes_inside_arg(self):
89 self.parseExpression('sed s#"bar baz"#"alpha beta"#g')
90 self.assertExecs(set(["sed"]))
91
92 def test_arg_continuation(self):
93 self.parseExpression("sed -i -e s,foo,bar,g \\\n *.pc")
94 self.assertExecs(set(["sed"]))
95
96 def test_dollar_in_quoted(self):
97 self.parseExpression('sed -i -e "foo$" *.pc')
98 self.assertExecs(set(["sed"]))
99
100 def test_quotes_inside_arg_continuation(self):
101 self.setEmptyVars(["bindir", "D", "libdir"])
102 self.parseExpression("""
103sed -i -e s#"moc_location=.*$"#"moc_location=${bindir}/moc4"# \\
104-e s#"uic_location=.*$"#"uic_location=${bindir}/uic4"# \\
105${D}${libdir}/pkgconfig/*.pc
106""")
107 self.assertReferences(set(["bindir", "D", "libdir"]))
108
109 def test_assign_subshell_expansion(self):
110 self.parseExpression("foo=$(echo bar)")
111 self.assertExecs(set(["echo"]))
112
113 def test_shell_unexpanded(self):
114 self.setEmptyVars(["QT_BASE_NAME"])
115 self.parseExpression('echo "${QT_BASE_NAME}"')
116 self.assertExecs(set(["echo"]))
117 self.assertReferences(set(["QT_BASE_NAME"]))
118
119 def test_incomplete_varexp_single_quotes(self):
120 self.parseExpression("sed -i -e 's:IP{:I${:g' $pc")
121 self.assertExecs(set(["sed"]))
122
123
124 def test_until(self):
125 self.parseExpression("until false; do echo true; done")
126 self.assertExecs(set(["false", "echo"]))
127 self.assertReferences(set())
128
129 def test_case(self):
130 self.parseExpression("""
131case $foo in
132*)
133bar
134;;
135esac
136""")
137 self.assertExecs(set(["bar"]))
138 self.assertReferences(set())
139
140 def test_assign_exec(self):
141 self.parseExpression("a=b c='foo bar' alpha 1 2 3")
142 self.assertExecs(set(["alpha"]))
143
144 def test_redirect_to_file(self):
145 self.setEmptyVars(["foo"])
146 self.parseExpression("echo foo >${foo}/bar")
147 self.assertExecs(set(["echo"]))
148 self.assertReferences(set(["foo"]))
149
150 def test_heredoc(self):
151 self.setEmptyVars(["theta"])
152 self.parseExpression("""
153cat <<END
154alpha
155beta
156${theta}
157END
158""")
159 self.assertReferences(set(["theta"]))
160
161 def test_redirect_from_heredoc(self):
162 v = ["B", "SHADOW_MAILDIR", "SHADOW_MAILFILE", "SHADOW_UTMPDIR", "SHADOW_LOGDIR", "bindir"]
163 self.setEmptyVars(v)
164 self.parseExpression("""
165cat <<END >${B}/cachedpaths
166shadow_cv_maildir=${SHADOW_MAILDIR}
167shadow_cv_mailfile=${SHADOW_MAILFILE}
168shadow_cv_utmpdir=${SHADOW_UTMPDIR}
169shadow_cv_logdir=${SHADOW_LOGDIR}
170shadow_cv_passwd_dir=${bindir}
171END
172""")
173 self.assertReferences(set(v))
174 self.assertExecs(set(["cat"]))
175
176# def test_incomplete_command_expansion(self):
177# self.assertRaises(reftracker.ShellSyntaxError, reftracker.execs,
178# bbvalue.shparse("cp foo`", self.d), self.d)
179
180# def test_rogue_dollarsign(self):
181# self.setValues({"D" : "/tmp"})
182# self.parseExpression("install -d ${D}$")
183# self.assertReferences(set(["D"]))
184# self.assertExecs(set(["install"]))
185
186
187class PythonReferenceTest(ReferenceTest):
188
189 def setUp(self):
190 self.d = bb.data.init()
191 if hasattr(bb.utils, "_context"):
192 self.context = bb.utils._context
193 else:
194 import __builtin__
195 self.context = __builtin__.__dict__
196
197 def parseExpression(self, exp):
198 parsedvar = self.d.expandWithRefs(exp, None)
199 parser = bb.codeparser.PythonParser("ParserTest", logger)
200 parser.parse_python(parsedvar.value)
201
202 self.references = parsedvar.references | parser.references
203 self.execs = parser.execs
204
205 @staticmethod
206 def indent(value):
207 """Python Snippets have to be indented, python values don't have to
208be. These unit tests are testing snippets."""
209 return " " + value
210
211 def test_getvar_reference(self):
212 self.parseExpression("bb.data.getVar('foo', d, True)")
213 self.assertReferences(set(["foo"]))
214 self.assertExecs(set())
215
216 def test_getvar_computed_reference(self):
217 self.parseExpression("bb.data.getVar('f' + 'o' + 'o', d, True)")
218 self.assertReferences(set())
219 self.assertExecs(set())
220
221 def test_getvar_exec_reference(self):
222 self.parseExpression("eval('bb.data.getVar(\"foo\", d, True)')")
223 self.assertReferences(set())
224 self.assertExecs(set(["eval"]))
225
226 def test_var_reference(self):
227 self.context["foo"] = lambda x: x
228 self.setEmptyVars(["FOO"])
229 self.parseExpression("foo('${FOO}')")
230 self.assertReferences(set(["FOO"]))
231 self.assertExecs(set(["foo"]))
232 del self.context["foo"]
233
234 def test_var_exec(self):
235 for etype in ("func", "task"):
236 self.d.setVar("do_something", "echo 'hi mom! ${FOO}'")
237 self.d.setVarFlag("do_something", etype, True)
238 self.parseExpression("bb.build.exec_func('do_something', d)")
239 self.assertReferences(set(["do_something"]))
240
241 def test_function_reference(self):
242 self.context["testfunc"] = lambda msg: bb.msg.note(1, None, msg)
243 self.d.setVar("FOO", "Hello, World!")
244 self.parseExpression("testfunc('${FOO}')")
245 self.assertReferences(set(["FOO"]))
246 self.assertExecs(set(["testfunc"]))
247 del self.context["testfunc"]
248
249 def test_qualified_function_reference(self):
250 self.parseExpression("time.time()")
251 self.assertExecs(set(["time.time"]))
252
253 def test_qualified_function_reference_2(self):
254 self.parseExpression("os.path.dirname('/foo/bar')")
255 self.assertExecs(set(["os.path.dirname"]))
256
257 def test_qualified_function_reference_nested(self):
258 self.parseExpression("time.strftime('%Y%m%d',time.gmtime())")
259 self.assertExecs(set(["time.strftime", "time.gmtime"]))
260
261 def test_function_reference_chained(self):
262 self.context["testget"] = lambda: "\tstrip me "
263 self.parseExpression("testget().strip()")
264 self.assertExecs(set(["testget"]))
265 del self.context["testget"]
266
267
268class DependencyReferenceTest(ReferenceTest):
269
270 pydata = """
271bb.data.getVar('somevar', d, True)
272def test(d):
273 foo = 'bar %s' % 'foo'
274def test2(d):
275 d.getVar(foo, True)
276 d.getVar('bar', False)
277 test2(d)
278
279def a():
280 \"\"\"some
281 stuff
282 \"\"\"
283 return "heh"
284
285test(d)
286
287bb.data.expand(bb.data.getVar("something", False, d), d)
288bb.data.expand("${inexpand} somethingelse", d)
289bb.data.getVar(a(), d, False)
290"""
291
292 def test_python(self):
293 self.d.setVar("FOO", self.pydata)
294 self.setEmptyVars(["inexpand", "a", "test2", "test"])
295 self.d.setVarFlags("FOO", {"func": True, "python": True})
296
297 deps, values = bb.data.build_dependencies("FOO", set(self.d.keys()), set(), set(), self.d)
298
299 self.assertEquals(deps, set(["somevar", "bar", "something", "inexpand", "test", "test2", "a"]))
300
301
302 shelldata = """
303foo () {
304bar
305}
306{
307echo baz
308$(heh)
309eval `moo`
310}
311a=b
312c=d
313(
314true && false
315test -f foo
316testval=something
317$testval
318) || aiee
319! inverted
320echo ${somevar}
321
322case foo in
323bar)
324echo bar
325;;
326baz)
327echo baz
328;;
329foo*)
330echo foo
331;;
332esac
333"""
334
335 def test_shell(self):
336 execs = ["bar", "echo", "heh", "moo", "true", "aiee"]
337 self.d.setVar("somevar", "heh")
338 self.d.setVar("inverted", "echo inverted...")
339 self.d.setVarFlag("inverted", "func", True)
340 self.d.setVar("FOO", self.shelldata)
341 self.d.setVarFlags("FOO", {"func": True})
342 self.setEmptyVars(execs)
343
344 deps, values = bb.data.build_dependencies("FOO", set(self.d.keys()), set(), set(), self.d)
345
346 self.assertEquals(deps, set(["somevar", "inverted"] + execs))
347
348
349 def test_vardeps(self):
350 self.d.setVar("oe_libinstall", "echo test")
351 self.d.setVar("FOO", "foo=oe_libinstall; eval $foo")
352 self.d.setVarFlag("FOO", "vardeps", "oe_libinstall")
353
354 deps, values = bb.data.build_dependencies("FOO", set(self.d.keys()), set(), set(), self.d)
355
356 self.assertEquals(deps, set(["oe_libinstall"]))
357
358 def test_vardeps_expand(self):
359 self.d.setVar("oe_libinstall", "echo test")
360 self.d.setVar("FOO", "foo=oe_libinstall; eval $foo")
361 self.d.setVarFlag("FOO", "vardeps", "${@'oe_libinstall'}")
362
363 deps, values = bb.data.build_dependencies("FOO", set(self.d.keys()), set(), set(), self.d)
364
365 self.assertEquals(deps, set(["oe_libinstall"]))
366
367 #Currently no wildcard support
368 #def test_vardeps_wildcards(self):
369 # self.d.setVar("oe_libinstall", "echo test")
370 # self.d.setVar("FOO", "foo=oe_libinstall; eval $foo")
371 # self.d.setVarFlag("FOO", "vardeps", "oe_*")
372 # self.assertEquals(deps, set(["oe_libinstall"]))
373
374