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