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