blob: f1cd83a419534e9f8b527fbd242cdac3f3e644d3 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# BitBake Tests for utils.py
5#
6# Copyright (C) 2012 Richard Purdie
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20#
21
22import unittest
23import bb
24import os
25import tempfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050026import re
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027
28class VerCmpString(unittest.TestCase):
29
30 def test_vercmpstring(self):
31 result = bb.utils.vercmp_string('1', '2')
32 self.assertTrue(result < 0)
33 result = bb.utils.vercmp_string('2', '1')
34 self.assertTrue(result > 0)
35 result = bb.utils.vercmp_string('1', '1.0')
36 self.assertTrue(result < 0)
37 result = bb.utils.vercmp_string('1', '1.1')
38 self.assertTrue(result < 0)
39 result = bb.utils.vercmp_string('1.1', '1_p2')
40 self.assertTrue(result < 0)
41 result = bb.utils.vercmp_string('1.0', '1.0+1.1-beta1')
42 self.assertTrue(result < 0)
43 result = bb.utils.vercmp_string('1.1', '1.0+1.1-beta1')
44 self.assertTrue(result > 0)
Brad Bishop19323692019-04-05 15:28:33 -040045 result = bb.utils.vercmp_string('1.', '1.1')
46 self.assertTrue(result < 0)
47 result = bb.utils.vercmp_string('1.1', '1.')
48 self.assertTrue(result > 0)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049
50 def test_explode_dep_versions(self):
51 correctresult = {"foo" : ["= 1.10"]}
52 result = bb.utils.explode_dep_versions2("foo (= 1.10)")
53 self.assertEqual(result, correctresult)
54 result = bb.utils.explode_dep_versions2("foo (=1.10)")
55 self.assertEqual(result, correctresult)
56 result = bb.utils.explode_dep_versions2("foo ( = 1.10)")
57 self.assertEqual(result, correctresult)
58 result = bb.utils.explode_dep_versions2("foo ( =1.10)")
59 self.assertEqual(result, correctresult)
60 result = bb.utils.explode_dep_versions2("foo ( = 1.10 )")
61 self.assertEqual(result, correctresult)
62 result = bb.utils.explode_dep_versions2("foo ( =1.10 )")
63 self.assertEqual(result, correctresult)
64
65 def test_vercmp_string_op(self):
66 compareops = [('1', '1', '=', True),
67 ('1', '1', '==', True),
68 ('1', '1', '!=', False),
69 ('1', '1', '>', False),
70 ('1', '1', '<', False),
71 ('1', '1', '>=', True),
72 ('1', '1', '<=', True),
73 ('1', '0', '=', False),
74 ('1', '0', '==', False),
75 ('1', '0', '!=', True),
76 ('1', '0', '>', True),
77 ('1', '0', '<', False),
78 ('1', '0', '>>', True),
79 ('1', '0', '<<', False),
80 ('1', '0', '>=', True),
81 ('1', '0', '<=', False),
82 ('0', '1', '=', False),
83 ('0', '1', '==', False),
84 ('0', '1', '!=', True),
85 ('0', '1', '>', False),
86 ('0', '1', '<', True),
87 ('0', '1', '>>', False),
88 ('0', '1', '<<', True),
89 ('0', '1', '>=', False),
90 ('0', '1', '<=', True)]
91
92 for arg1, arg2, op, correctresult in compareops:
93 result = bb.utils.vercmp_string_op(arg1, arg2, op)
94 self.assertEqual(result, correctresult, 'vercmp_string_op("%s", "%s", "%s") != %s' % (arg1, arg2, op, correctresult))
95
96 # Check that clearly invalid operator raises an exception
97 self.assertRaises(bb.utils.VersionStringException, bb.utils.vercmp_string_op, '0', '0', '$')
98
99
100class Path(unittest.TestCase):
101 def test_unsafe_delete_path(self):
102 checkitems = [('/', True),
103 ('//', True),
104 ('///', True),
105 (os.getcwd().count(os.sep) * ('..' + os.sep), True),
106 (os.environ.get('HOME', '/home/test'), True),
107 ('/home/someone', True),
108 ('/home/other/', True),
109 ('/home/other/subdir', False),
110 ('', False)]
111 for arg1, correctresult in checkitems:
112 result = bb.utils._check_unsafe_delete_path(arg1)
113 self.assertEqual(result, correctresult, '_check_unsafe_delete_path("%s") != %s' % (arg1, correctresult))
114
115
116class EditMetadataFile(unittest.TestCase):
117 _origfile = """
118# A comment
119HELLO = "oldvalue"
120
121THIS = "that"
122
123# Another comment
124NOCHANGE = "samevalue"
125OTHER = 'anothervalue'
126
127MULTILINE = "a1 \\
128 a2 \\
129 a3"
130
131MULTILINE2 := " \\
132 b1 \\
133 b2 \\
134 b3 \\
135 "
136
137
138MULTILINE3 = " \\
139 c1 \\
140 c2 \\
141 c3 \\
142"
143
144do_functionname() {
145 command1 ${VAL1} ${VAL2}
146 command2 ${VAL3} ${VAL4}
147}
148"""
149 def _testeditfile(self, varvalues, compareto, dummyvars=None):
150 if dummyvars is None:
151 dummyvars = []
152 with tempfile.NamedTemporaryFile('w', delete=False) as tf:
153 tf.write(self._origfile)
154 tf.close()
155 try:
156 varcalls = []
157 def handle_file(varname, origvalue, op, newlines):
158 self.assertIn(varname, varvalues, 'Callback called for variable %s not in the list!' % varname)
159 self.assertNotIn(varname, dummyvars, 'Callback called for variable %s in dummy list!' % varname)
160 varcalls.append(varname)
161 return varvalues[varname]
162
163 bb.utils.edit_metadata_file(tf.name, varvalues.keys(), handle_file)
164 with open(tf.name) as f:
165 modfile = f.readlines()
166 # Ensure the output matches the expected output
167 self.assertEqual(compareto.splitlines(True), modfile)
168 # Ensure the callback function was called for every variable we asked for
169 # (plus allow testing behaviour when a requested variable is not present)
170 self.assertEqual(sorted(varvalues.keys()), sorted(varcalls + dummyvars))
171 finally:
172 os.remove(tf.name)
173
174
175 def test_edit_metadata_file_nochange(self):
176 # Test file doesn't get modified with nothing to do
177 self._testeditfile({}, self._origfile)
178 # Test file doesn't get modified with only dummy variables
179 self._testeditfile({'DUMMY1': ('should_not_set', None, 0, True),
180 'DUMMY2': ('should_not_set_again', None, 0, True)}, self._origfile, dummyvars=['DUMMY1', 'DUMMY2'])
181 # Test file doesn't get modified with some the same values
182 self._testeditfile({'THIS': ('that', None, 0, True),
183 'OTHER': ('anothervalue', None, 0, True),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500184 'MULTILINE3': (' c1 c2 c3 ', None, 4, False)}, self._origfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185
186 def test_edit_metadata_file_1(self):
187
188 newfile1 = """
189# A comment
190HELLO = "newvalue"
191
192THIS = "that"
193
194# Another comment
195NOCHANGE = "samevalue"
196OTHER = 'anothervalue'
197
198MULTILINE = "a1 \\
199 a2 \\
200 a3"
201
202MULTILINE2 := " \\
203 b1 \\
204 b2 \\
205 b3 \\
206 "
207
208
209MULTILINE3 = " \\
210 c1 \\
211 c2 \\
212 c3 \\
213"
214
215do_functionname() {
216 command1 ${VAL1} ${VAL2}
217 command2 ${VAL3} ${VAL4}
218}
219"""
220 self._testeditfile({'HELLO': ('newvalue', None, 4, True)}, newfile1)
221
222
223 def test_edit_metadata_file_2(self):
224
225 newfile2 = """
226# A comment
227HELLO = "oldvalue"
228
229THIS = "that"
230
231# Another comment
232NOCHANGE = "samevalue"
233OTHER = 'anothervalue'
234
235MULTILINE = " \\
236 d1 \\
237 d2 \\
238 d3 \\
239 "
240
241MULTILINE2 := " \\
242 b1 \\
243 b2 \\
244 b3 \\
245 "
246
247
248MULTILINE3 = "nowsingle"
249
250do_functionname() {
251 command1 ${VAL1} ${VAL2}
252 command2 ${VAL3} ${VAL4}
253}
254"""
255 self._testeditfile({'MULTILINE': (['d1','d2','d3'], None, 4, False),
256 'MULTILINE3': ('nowsingle', None, 4, True),
257 'NOTPRESENT': (['a', 'b'], None, 4, False)}, newfile2, dummyvars=['NOTPRESENT'])
258
259
260 def test_edit_metadata_file_3(self):
261
262 newfile3 = """
263# A comment
264HELLO = "oldvalue"
265
266# Another comment
267NOCHANGE = "samevalue"
268OTHER = "yetanothervalue"
269
270MULTILINE = "e1 \\
271 e2 \\
272 e3 \\
273 "
274
275MULTILINE2 := "f1 \\
276\tf2 \\
277\t"
278
279
280MULTILINE3 = " \\
281 c1 \\
282 c2 \\
283 c3 \\
284"
285
286do_functionname() {
287 othercommand_one a b c
288 othercommand_two d e f
289}
290"""
291
292 self._testeditfile({'do_functionname()': (['othercommand_one a b c', 'othercommand_two d e f'], None, 4, False),
293 'MULTILINE2': (['f1', 'f2'], None, '\t', True),
294 'MULTILINE': (['e1', 'e2', 'e3'], None, -1, True),
295 'THIS': (None, None, 0, False),
296 'OTHER': ('yetanothervalue', None, 0, True)}, newfile3)
297
298
299 def test_edit_metadata_file_4(self):
300
301 newfile4 = """
302# A comment
303HELLO = "oldvalue"
304
305THIS = "that"
306
307# Another comment
308OTHER = 'anothervalue'
309
310MULTILINE = "a1 \\
311 a2 \\
312 a3"
313
314MULTILINE2 := " \\
315 b1 \\
316 b2 \\
317 b3 \\
318 "
319
320
321"""
322
323 self._testeditfile({'NOCHANGE': (None, None, 0, False),
324 'MULTILINE3': (None, None, 0, False),
325 'THIS': ('that', None, 0, False),
326 'do_functionname()': (None, None, 0, False)}, newfile4)
327
328
329 def test_edit_metadata(self):
330 newfile5 = """
331# A comment
332HELLO = "hithere"
333
334# A new comment
335THIS += "that"
336
337# Another comment
338NOCHANGE = "samevalue"
339OTHER = 'anothervalue'
340
341MULTILINE = "a1 \\
342 a2 \\
343 a3"
344
345MULTILINE2 := " \\
346 b1 \\
347 b2 \\
348 b3 \\
349 "
350
351
352MULTILINE3 = " \\
353 c1 \\
354 c2 \\
355 c3 \\
356"
357
358NEWVAR = "value"
359
360do_functionname() {
361 command1 ${VAL1} ${VAL2}
362 command2 ${VAL3} ${VAL4}
363}
364"""
365
366
367 def handle_var(varname, origvalue, op, newlines):
368 if varname == 'THIS':
369 newlines.append('# A new comment\n')
370 elif varname == 'do_functionname()':
371 newlines.append('NEWVAR = "value"\n')
372 newlines.append('\n')
373 valueitem = varvalues.get(varname, None)
374 if valueitem:
375 return valueitem
376 else:
377 return (origvalue, op, 0, True)
378
379 varvalues = {'HELLO': ('hithere', None, 0, True), 'THIS': ('that', '+=', 0, True)}
380 varlist = ['HELLO', 'THIS', 'do_functionname()']
381 (updated, newlines) = bb.utils.edit_metadata(self._origfile.splitlines(True), varlist, handle_var)
382 self.assertTrue(updated, 'List should be updated but isn\'t')
383 self.assertEqual(newlines, newfile5.splitlines(True))
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500384
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500385 # Make sure the orig value matches what we expect it to be
386 def test_edit_metadata_origvalue(self):
387 origfile = """
388MULTILINE = " stuff \\
389 morestuff"
390"""
391 expected_value = "stuff morestuff"
392 global value_in_callback
393 value_in_callback = ""
394
395 def handle_var(varname, origvalue, op, newlines):
396 global value_in_callback
397 value_in_callback = origvalue
398 return (origvalue, op, -1, False)
399
400 bb.utils.edit_metadata(origfile.splitlines(True),
401 ['MULTILINE'],
402 handle_var)
403
404 testvalue = re.sub('\s+', ' ', value_in_callback.strip())
405 self.assertEqual(expected_value, testvalue)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500406
407class EditBbLayersConf(unittest.TestCase):
408
409 def _test_bblayers_edit(self, before, after, add, remove, notadded, notremoved):
410 with tempfile.NamedTemporaryFile('w', delete=False) as tf:
411 tf.write(before)
412 tf.close()
413 try:
414 actual_notadded, actual_notremoved = bb.utils.edit_bblayers_conf(tf.name, add, remove)
415 with open(tf.name) as f:
416 actual_after = f.readlines()
417 self.assertEqual(after.splitlines(True), actual_after)
418 self.assertEqual(notadded, actual_notadded)
419 self.assertEqual(notremoved, actual_notremoved)
420 finally:
421 os.remove(tf.name)
422
423
424 def test_bblayers_remove(self):
425 before = r"""
426# A comment
427
428BBPATH = "${TOPDIR}"
429BBFILES ?= ""
430BBLAYERS = " \
431 /home/user/path/layer1 \
432 /home/user/path/layer2 \
433 /home/user/path/subpath/layer3 \
434 /home/user/path/layer4 \
435 "
436"""
437 after = r"""
438# A comment
439
440BBPATH = "${TOPDIR}"
441BBFILES ?= ""
442BBLAYERS = " \
443 /home/user/path/layer1 \
444 /home/user/path/subpath/layer3 \
445 /home/user/path/layer4 \
446 "
447"""
448 self._test_bblayers_edit(before, after,
449 None,
450 '/home/user/path/layer2',
451 [],
452 [])
453
454
455 def test_bblayers_add(self):
456 before = r"""
457# A comment
458
459BBPATH = "${TOPDIR}"
460BBFILES ?= ""
461BBLAYERS = " \
462 /home/user/path/layer1 \
463 /home/user/path/layer2 \
464 /home/user/path/subpath/layer3 \
465 /home/user/path/layer4 \
466 "
467"""
468 after = r"""
469# A comment
470
471BBPATH = "${TOPDIR}"
472BBFILES ?= ""
473BBLAYERS = " \
474 /home/user/path/layer1 \
475 /home/user/path/layer2 \
476 /home/user/path/subpath/layer3 \
477 /home/user/path/layer4 \
478 /other/path/to/layer5 \
479 "
480"""
481 self._test_bblayers_edit(before, after,
482 '/other/path/to/layer5/',
483 None,
484 [],
485 [])
486
487
488 def test_bblayers_add_remove(self):
489 before = r"""
490# A comment
491
492BBPATH = "${TOPDIR}"
493BBFILES ?= ""
494BBLAYERS = " \
495 /home/user/path/layer1 \
496 /home/user/path/layer2 \
497 /home/user/path/subpath/layer3 \
498 /home/user/path/layer4 \
499 "
500"""
501 after = r"""
502# A comment
503
504BBPATH = "${TOPDIR}"
505BBFILES ?= ""
506BBLAYERS = " \
507 /home/user/path/layer1 \
508 /home/user/path/layer2 \
509 /home/user/path/layer4 \
510 /other/path/to/layer5 \
511 "
512"""
513 self._test_bblayers_edit(before, after,
514 ['/other/path/to/layer5', '/home/user/path/layer2/'], '/home/user/path/subpath/layer3/',
515 ['/home/user/path/layer2'],
516 [])
517
518
519 def test_bblayers_add_remove_home(self):
520 before = r"""
521# A comment
522
523BBPATH = "${TOPDIR}"
524BBFILES ?= ""
525BBLAYERS = " \
526 ~/path/layer1 \
527 ~/path/layer2 \
528 ~/otherpath/layer3 \
529 ~/path/layer4 \
530 "
531"""
532 after = r"""
533# A comment
534
535BBPATH = "${TOPDIR}"
536BBFILES ?= ""
537BBLAYERS = " \
538 ~/path/layer2 \
539 ~/path/layer4 \
540 ~/path2/layer5 \
541 "
542"""
543 self._test_bblayers_edit(before, after,
544 [os.environ['HOME'] + '/path/layer4', '~/path2/layer5'],
545 [os.environ['HOME'] + '/otherpath/layer3', '~/path/layer1', '~/path/notinlist'],
546 [os.environ['HOME'] + '/path/layer4'],
547 ['~/path/notinlist'])
548
549
550 def test_bblayers_add_remove_plusequals(self):
551 before = r"""
552# A comment
553
554BBPATH = "${TOPDIR}"
555BBFILES ?= ""
556BBLAYERS += " \
557 /home/user/path/layer1 \
558 /home/user/path/layer2 \
559 "
560"""
561 after = r"""
562# A comment
563
564BBPATH = "${TOPDIR}"
565BBFILES ?= ""
566BBLAYERS += " \
567 /home/user/path/layer2 \
568 /home/user/path/layer3 \
569 "
570"""
571 self._test_bblayers_edit(before, after,
572 '/home/user/path/layer3',
573 '/home/user/path/layer1',
574 [],
575 [])
576
577
578 def test_bblayers_add_remove_plusequals2(self):
579 before = r"""
580# A comment
581
582BBPATH = "${TOPDIR}"
583BBFILES ?= ""
584BBLAYERS += " \
585 /home/user/path/layer1 \
586 /home/user/path/layer2 \
587 /home/user/path/layer3 \
588 "
589BBLAYERS += "/home/user/path/layer4"
590BBLAYERS += "/home/user/path/layer5"
591"""
592 after = r"""
593# A comment
594
595BBPATH = "${TOPDIR}"
596BBFILES ?= ""
597BBLAYERS += " \
598 /home/user/path/layer2 \
599 /home/user/path/layer3 \
600 "
601BBLAYERS += "/home/user/path/layer5"
602BBLAYERS += "/home/user/otherpath/layer6"
603"""
604 self._test_bblayers_edit(before, after,
605 ['/home/user/otherpath/layer6', '/home/user/path/layer3'], ['/home/user/path/layer1', '/home/user/path/layer4', '/home/user/path/layer7'],
606 ['/home/user/path/layer3'],
607 ['/home/user/path/layer7'])