2c62c8a0f8145487bd2cab6f2174fc293b905830
[oweals/u-boot.git] / tools / binman / cbfs_util_test.py
1 #!/usr/bin/env python
2 # SPDX-License-Identifier: GPL-2.0+
3 # Copyright 2019 Google LLC
4 # Written by Simon Glass <sjg@chromium.org>
5
6 """Tests for cbfs_util
7
8 These create and read various CBFSs and compare the results with expected
9 values and with cbfstool
10 """
11
12 import io
13 import os
14 import shutil
15 import struct
16 import tempfile
17 import unittest
18
19 from binman import cbfs_util
20 from binman.cbfs_util import CbfsWriter
21 from binman import elf
22 from patman import test_util
23 from patman import tools
24
25 U_BOOT_DATA           = b'1234'
26 U_BOOT_DTB_DATA       = b'udtb'
27 COMPRESS_DATA         = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
28
29
30 class TestCbfs(unittest.TestCase):
31     """Test of cbfs_util classes"""
32     #pylint: disable=W0212
33     @classmethod
34     def setUpClass(cls):
35         # Create a temporary directory for test files
36         cls._indir = tempfile.mkdtemp(prefix='cbfs_util.')
37         tools.SetInputDirs([cls._indir])
38
39         # Set up some useful data files
40         TestCbfs._make_input_file('u-boot.bin', U_BOOT_DATA)
41         TestCbfs._make_input_file('u-boot.dtb', U_BOOT_DTB_DATA)
42         TestCbfs._make_input_file('compress', COMPRESS_DATA)
43
44         # Set up a temporary output directory, used by the tools library when
45         # compressing files
46         tools.PrepareOutputDir(None)
47
48         cls.have_cbfstool = True
49         try:
50             tools.Run('which', 'cbfstool')
51         except:
52             cls.have_cbfstool = False
53
54         cls.have_lz4 = True
55         try:
56             tools.Run('lz4', '--no-frame-crc', '-c',
57                       tools.GetInputFilename('u-boot.bin'), binary=True)
58         except:
59             cls.have_lz4 = False
60
61     @classmethod
62     def tearDownClass(cls):
63         """Remove the temporary input directory and its contents"""
64         if cls._indir:
65             shutil.rmtree(cls._indir)
66         cls._indir = None
67         tools.FinaliseOutputDir()
68
69     @classmethod
70     def _make_input_file(cls, fname, contents):
71         """Create a new test input file, creating directories as needed
72
73         Args:
74             fname: Filename to create
75             contents: File contents to write in to the file
76         Returns:
77             Full pathname of file created
78         """
79         pathname = os.path.join(cls._indir, fname)
80         tools.WriteFile(pathname, contents)
81         return pathname
82
83     def _check_hdr(self, data, size, offset=0, arch=cbfs_util.ARCHITECTURE_X86):
84         """Check that the CBFS has the expected header
85
86         Args:
87             data: Data to check
88             size: Expected ROM size
89             offset: Expected offset to first CBFS file
90             arch: Expected architecture
91
92         Returns:
93             CbfsReader object containing the CBFS
94         """
95         cbfs = cbfs_util.CbfsReader(data)
96         self.assertEqual(cbfs_util.HEADER_MAGIC, cbfs.magic)
97         self.assertEqual(cbfs_util.HEADER_VERSION2, cbfs.version)
98         self.assertEqual(size, cbfs.rom_size)
99         self.assertEqual(0, cbfs.boot_block_size)
100         self.assertEqual(cbfs_util.ENTRY_ALIGN, cbfs.align)
101         self.assertEqual(offset, cbfs.cbfs_offset)
102         self.assertEqual(arch, cbfs.arch)
103         return cbfs
104
105     def _check_uboot(self, cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x38,
106                      data=U_BOOT_DATA, cbfs_offset=None):
107         """Check that the U-Boot file is as expected
108
109         Args:
110             cbfs: CbfsReader object to check
111             ftype: Expected file type
112             offset: Expected offset of file
113             data: Expected data in file
114             cbfs_offset: Expected CBFS offset for file's data
115
116         Returns:
117             CbfsFile object containing the file
118         """
119         self.assertIn('u-boot', cbfs.files)
120         cfile = cbfs.files['u-boot']
121         self.assertEqual('u-boot', cfile.name)
122         self.assertEqual(offset, cfile.offset)
123         if cbfs_offset is not None:
124             self.assertEqual(cbfs_offset, cfile.cbfs_offset)
125         self.assertEqual(data, cfile.data)
126         self.assertEqual(ftype, cfile.ftype)
127         self.assertEqual(cbfs_util.COMPRESS_NONE, cfile.compress)
128         self.assertEqual(len(data), cfile.memlen)
129         return cfile
130
131     def _check_dtb(self, cbfs, offset=0x38, data=U_BOOT_DTB_DATA,
132                    cbfs_offset=None):
133         """Check that the U-Boot dtb file is as expected
134
135         Args:
136             cbfs: CbfsReader object to check
137             offset: Expected offset of file
138             data: Expected data in file
139             cbfs_offset: Expected CBFS offset for file's data
140         """
141         self.assertIn('u-boot-dtb', cbfs.files)
142         cfile = cbfs.files['u-boot-dtb']
143         self.assertEqual('u-boot-dtb', cfile.name)
144         self.assertEqual(offset, cfile.offset)
145         if cbfs_offset is not None:
146             self.assertEqual(cbfs_offset, cfile.cbfs_offset)
147         self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
148         self.assertEqual(cbfs_util.TYPE_RAW, cfile.ftype)
149         self.assertEqual(cbfs_util.COMPRESS_NONE, cfile.compress)
150         self.assertEqual(len(U_BOOT_DTB_DATA), cfile.memlen)
151
152     def _check_raw(self, data, size, offset=0, arch=cbfs_util.ARCHITECTURE_X86):
153         """Check that two raw files are added as expected
154
155         Args:
156             data: Data to check
157             size: Expected ROM size
158             offset: Expected offset to first CBFS file
159             arch: Expected architecture
160         """
161         cbfs = self._check_hdr(data, size, offset=offset, arch=arch)
162         self._check_uboot(cbfs)
163         self._check_dtb(cbfs)
164
165     def _get_expected_cbfs(self, size, arch='x86', compress=None, base=None):
166         """Get the file created by cbfstool for a particular scenario
167
168         Args:
169             size: Size of the CBFS in bytes
170             arch: Architecture of the CBFS, as a string
171             compress: Compression to use, e.g. cbfs_util.COMPRESS_LZMA
172             base: Base address of file, or None to put it anywhere
173
174         Returns:
175             Resulting CBFS file, or None if cbfstool is not available
176         """
177         if not self.have_cbfstool or not self.have_lz4:
178             return None
179         cbfs_fname = os.path.join(self._indir, 'test.cbfs')
180         cbfs_util.cbfstool(cbfs_fname, 'create', '-m', arch, '-s', '%#x' % size)
181         if base:
182             base = [(1 << 32) - size + b for b in base]
183         cbfs_util.cbfstool(cbfs_fname, 'add', '-n', 'u-boot', '-t', 'raw',
184                            '-c', compress and compress[0] or 'none',
185                            '-f', tools.GetInputFilename(
186                                compress and 'compress' or 'u-boot.bin'),
187                            base=base[0] if base else None)
188         cbfs_util.cbfstool(cbfs_fname, 'add', '-n', 'u-boot-dtb', '-t', 'raw',
189                            '-c', compress and compress[1] or 'none',
190                            '-f', tools.GetInputFilename(
191                                compress and 'compress' or 'u-boot.dtb'),
192                            base=base[1] if base else None)
193         return cbfs_fname
194
195     def _compare_expected_cbfs(self, data, cbfstool_fname):
196         """Compare against what cbfstool creates
197
198         This compares what binman creates with what cbfstool creates for what
199         is proportedly the same thing.
200
201         Args:
202             data: CBFS created by binman
203             cbfstool_fname: CBFS created by cbfstool
204         """
205         if not self.have_cbfstool or not self.have_lz4:
206             return
207         expect = tools.ReadFile(cbfstool_fname)
208         if expect != data:
209             tools.WriteFile('/tmp/expect', expect)
210             tools.WriteFile('/tmp/actual', data)
211             print('diff -y <(xxd -g1 /tmp/expect) <(xxd -g1 /tmp/actual) | colordiff')
212             self.fail('cbfstool produced a different result')
213
214     def test_cbfs_functions(self):
215         """Test global functions of cbfs_util"""
216         self.assertEqual(cbfs_util.ARCHITECTURE_X86, cbfs_util.find_arch('x86'))
217         self.assertIsNone(cbfs_util.find_arch('bad-arch'))
218
219         self.assertEqual(cbfs_util.COMPRESS_LZMA, cbfs_util.find_compress('lzma'))
220         self.assertIsNone(cbfs_util.find_compress('bad-comp'))
221
222     def test_cbfstool_failure(self):
223         """Test failure to run cbfstool"""
224         if not self.have_cbfstool:
225             self.skipTest('No cbfstool available')
226         try:
227             # In verbose mode this test fails since stderr is not captured. Fix
228             # this by turning off verbosity.
229             old_verbose = cbfs_util.VERBOSE
230             cbfs_util.VERBOSE = False
231             with test_util.capture_sys_output() as (_stdout, stderr):
232                 with self.assertRaises(Exception) as e:
233                     cbfs_util.cbfstool('missing-file', 'bad-command')
234         finally:
235             cbfs_util.VERBOSE = old_verbose
236         self.assertIn('Unknown command', stderr.getvalue())
237         self.assertIn('Failed to run', str(e.exception))
238
239     def test_cbfs_raw(self):
240         """Test base handling of a Coreboot Filesystem (CBFS)"""
241         size = 0xb0
242         cbw = CbfsWriter(size)
243         cbw.add_file_raw('u-boot', U_BOOT_DATA)
244         cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
245         data = cbw.get_data()
246         self._check_raw(data, size)
247         cbfs_fname = self._get_expected_cbfs(size=size)
248         self._compare_expected_cbfs(data, cbfs_fname)
249
250     def test_cbfs_invalid_file_type(self):
251         """Check handling of an invalid file type when outputiing a CBFS"""
252         size = 0xb0
253         cbw = CbfsWriter(size)
254         cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA)
255
256         # Change the type manually before generating the CBFS, and make sure
257         # that the generator complains
258         cfile.ftype = 0xff
259         with self.assertRaises(ValueError) as e:
260             cbw.get_data()
261         self.assertIn('Unknown type 0xff when writing', str(e.exception))
262
263     def test_cbfs_invalid_file_type_on_read(self):
264         """Check handling of an invalid file type when reading the CBFS"""
265         size = 0xb0
266         cbw = CbfsWriter(size)
267         cbw.add_file_raw('u-boot', U_BOOT_DATA)
268
269         data = cbw.get_data()
270
271         # Read in the first file header
272         cbr = cbfs_util.CbfsReader(data, read=False)
273         with io.BytesIO(data) as fd:
274             self.assertTrue(cbr._find_and_read_header(fd, len(data)))
275             pos = fd.tell()
276             hdr_data = fd.read(cbfs_util.FILE_HEADER_LEN)
277             magic, size, ftype, attr, offset = struct.unpack(
278                 cbfs_util.FILE_HEADER_FORMAT, hdr_data)
279
280         # Create a new CBFS with a change to the file type
281         ftype = 0xff
282         newdata = data[:pos]
283         newdata += struct.pack(cbfs_util.FILE_HEADER_FORMAT, magic, size, ftype,
284                                attr, offset)
285         newdata += data[pos + cbfs_util.FILE_HEADER_LEN:]
286
287         # Read in this CBFS and make sure that the reader complains
288         with self.assertRaises(ValueError) as e:
289             cbfs_util.CbfsReader(newdata)
290         self.assertIn('Unknown type 0xff when reading', str(e.exception))
291
292     def test_cbfs_no_space(self):
293         """Check handling of running out of space in the CBFS"""
294         size = 0x60
295         cbw = CbfsWriter(size)
296         cbw.add_file_raw('u-boot', U_BOOT_DATA)
297         with self.assertRaises(ValueError) as e:
298             cbw.get_data()
299         self.assertIn('No space for header', str(e.exception))
300
301     def test_cbfs_no_space_skip(self):
302         """Check handling of running out of space in CBFS with file header"""
303         size = 0x5c
304         cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64)
305         cbw._add_fileheader = True
306         cbw.add_file_raw('u-boot', U_BOOT_DATA)
307         with self.assertRaises(ValueError) as e:
308             cbw.get_data()
309         self.assertIn('No space for data before offset', str(e.exception))
310
311     def test_cbfs_no_space_pad(self):
312         """Check handling of running out of space in CBFS with file header"""
313         size = 0x70
314         cbw = CbfsWriter(size)
315         cbw._add_fileheader = True
316         cbw.add_file_raw('u-boot', U_BOOT_DATA)
317         with self.assertRaises(ValueError) as e:
318             cbw.get_data()
319         self.assertIn('No space for data before pad offset', str(e.exception))
320
321     def test_cbfs_bad_header_ptr(self):
322         """Check handling of a bad master-header pointer"""
323         size = 0x70
324         cbw = CbfsWriter(size)
325         cbw.add_file_raw('u-boot', U_BOOT_DATA)
326         data = cbw.get_data()
327
328         # Add one to the pointer to make it invalid
329         newdata = data[:-4] + struct.pack('<I', cbw._header_offset + 1)
330
331         # We should still be able to find the master header by searching
332         with test_util.capture_sys_output() as (stdout, _stderr):
333             cbfs = cbfs_util.CbfsReader(newdata)
334         self.assertIn('Relative offset seems wrong', stdout.getvalue())
335         self.assertIn('u-boot', cbfs.files)
336         self.assertEqual(size, cbfs.rom_size)
337
338     def test_cbfs_bad_header(self):
339         """Check handling of a bad master header"""
340         size = 0x70
341         cbw = CbfsWriter(size)
342         cbw.add_file_raw('u-boot', U_BOOT_DATA)
343         data = cbw.get_data()
344
345         # Drop most of the header and try reading the modified CBFS
346         newdata = data[:cbw._header_offset + 4]
347
348         with test_util.capture_sys_output() as (stdout, _stderr):
349             with self.assertRaises(ValueError) as e:
350                 cbfs_util.CbfsReader(newdata)
351         self.assertIn('Relative offset seems wrong', stdout.getvalue())
352         self.assertIn('Cannot find master header', str(e.exception))
353
354     def test_cbfs_bad_file_header(self):
355         """Check handling of a bad file header"""
356         size = 0x70
357         cbw = CbfsWriter(size)
358         cbw.add_file_raw('u-boot', U_BOOT_DATA)
359         data = cbw.get_data()
360
361         # Read in the CBFS master header (only), then stop
362         cbr = cbfs_util.CbfsReader(data, read=False)
363         with io.BytesIO(data) as fd:
364             self.assertTrue(cbr._find_and_read_header(fd, len(data)))
365             pos = fd.tell()
366
367         # Remove all but 4 bytes of the file headerm and try to read the file
368         newdata = data[:pos + 4]
369         with test_util.capture_sys_output() as (stdout, _stderr):
370             with io.BytesIO(newdata) as fd:
371                 fd.seek(pos)
372                 self.assertEqual(False, cbr._read_next_file(fd))
373         self.assertIn('File header at 0x0 ran out of data', stdout.getvalue())
374
375     def test_cbfs_bad_file_string(self):
376         """Check handling of an incomplete filename string"""
377         size = 0x70
378         cbw = CbfsWriter(size)
379         cbw.add_file_raw('16-characters xx', U_BOOT_DATA)
380         data = cbw.get_data()
381
382         # Read in the CBFS master header (only), then stop
383         cbr = cbfs_util.CbfsReader(data, read=False)
384         with io.BytesIO(data) as fd:
385             self.assertTrue(cbr._find_and_read_header(fd, len(data)))
386             pos = fd.tell()
387
388         # Create a new CBFS with only the first 16 bytes of the file name, then
389         # try to read the file
390         newdata = data[:pos + cbfs_util.FILE_HEADER_LEN + 16]
391         with test_util.capture_sys_output() as (stdout, _stderr):
392             with io.BytesIO(newdata) as fd:
393                 fd.seek(pos)
394                 self.assertEqual(False, cbr._read_next_file(fd))
395         self.assertIn('String at %#x ran out of data' %
396                       cbfs_util.FILE_HEADER_LEN, stdout.getvalue())
397
398     def test_cbfs_debug(self):
399         """Check debug output"""
400         size = 0x70
401         cbw = CbfsWriter(size)
402         cbw.add_file_raw('u-boot', U_BOOT_DATA)
403         data = cbw.get_data()
404
405         try:
406             cbfs_util.DEBUG = True
407             with test_util.capture_sys_output() as (stdout, _stderr):
408                 cbfs_util.CbfsReader(data)
409             self.assertEqual('name u-boot\ndata %s\n' % U_BOOT_DATA,
410                              stdout.getvalue())
411         finally:
412             cbfs_util.DEBUG = False
413
414     def test_cbfs_bad_attribute(self):
415         """Check handling of bad attribute tag"""
416         if not self.have_lz4:
417             self.skipTest('lz4 --no-frame-crc not available')
418         size = 0x140
419         cbw = CbfsWriter(size)
420         cbw.add_file_raw('u-boot', COMPRESS_DATA, None,
421                          compress=cbfs_util.COMPRESS_LZ4)
422         data = cbw.get_data()
423
424         # Search the CBFS for the expected compression tag
425         with io.BytesIO(data) as fd:
426             while True:
427                 pos = fd.tell()
428                 tag, = struct.unpack('>I', fd.read(4))
429                 if tag == cbfs_util.FILE_ATTR_TAG_COMPRESSION:
430                     break
431
432         # Create a new CBFS with the tag changed to something invalid
433         newdata = data[:pos] + struct.pack('>I', 0x123) + data[pos + 4:]
434         with test_util.capture_sys_output() as (stdout, _stderr):
435             cbfs_util.CbfsReader(newdata)
436         self.assertEqual('Unknown attribute tag 123\n', stdout.getvalue())
437
438     def test_cbfs_missing_attribute(self):
439         """Check handling of an incomplete attribute tag"""
440         if not self.have_lz4:
441             self.skipTest('lz4 --no-frame-crc not available')
442         size = 0x140
443         cbw = CbfsWriter(size)
444         cbw.add_file_raw('u-boot', COMPRESS_DATA, None,
445                          compress=cbfs_util.COMPRESS_LZ4)
446         data = cbw.get_data()
447
448         # Read in the CBFS master header (only), then stop
449         cbr = cbfs_util.CbfsReader(data, read=False)
450         with io.BytesIO(data) as fd:
451             self.assertTrue(cbr._find_and_read_header(fd, len(data)))
452             pos = fd.tell()
453
454         # Create a new CBFS with only the first 4 bytes of the compression tag,
455         # then try to read the file
456         tag_pos = pos + cbfs_util.FILE_HEADER_LEN + cbfs_util.FILENAME_ALIGN
457         newdata = data[:tag_pos + 4]
458         with test_util.capture_sys_output() as (stdout, _stderr):
459             with io.BytesIO(newdata) as fd:
460                 fd.seek(pos)
461                 self.assertEqual(False, cbr._read_next_file(fd))
462         self.assertIn('Attribute tag at %x ran out of data' % tag_pos,
463                       stdout.getvalue())
464
465     def test_cbfs_file_master_header(self):
466         """Check handling of a file containing a master header"""
467         size = 0x100
468         cbw = CbfsWriter(size)
469         cbw._add_fileheader = True
470         cbw.add_file_raw('u-boot', U_BOOT_DATA)
471         data = cbw.get_data()
472
473         cbr = cbfs_util.CbfsReader(data)
474         self.assertIn('u-boot', cbr.files)
475         self.assertEqual(size, cbr.rom_size)
476
477     def test_cbfs_arch(self):
478         """Test on non-x86 architecture"""
479         size = 0x100
480         cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64)
481         cbw.add_file_raw('u-boot', U_BOOT_DATA)
482         cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
483         data = cbw.get_data()
484         self._check_raw(data, size, offset=0x40,
485                         arch=cbfs_util.ARCHITECTURE_PPC64)
486
487         # Compare against what cbfstool creates
488         cbfs_fname = self._get_expected_cbfs(size=size, arch='ppc64')
489         self._compare_expected_cbfs(data, cbfs_fname)
490
491     def test_cbfs_stage(self):
492         """Tests handling of a Coreboot Filesystem (CBFS)"""
493         if not elf.ELF_TOOLS:
494             self.skipTest('Python elftools not available')
495         elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
496         elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
497
498         size = 0xb0
499         cbw = CbfsWriter(size)
500         cbw.add_file_stage('u-boot', tools.ReadFile(elf_fname))
501
502         data = cbw.get_data()
503         cbfs = self._check_hdr(data, size)
504         load = 0xfef20000
505         entry = load + 2
506
507         cfile = self._check_uboot(cbfs, cbfs_util.TYPE_STAGE, offset=0x28,
508                                   data=U_BOOT_DATA + U_BOOT_DTB_DATA)
509
510         self.assertEqual(entry, cfile.entry)
511         self.assertEqual(load, cfile.load)
512         self.assertEqual(len(U_BOOT_DATA) + len(U_BOOT_DTB_DATA),
513                          cfile.data_len)
514
515         # Compare against what cbfstool creates
516         if self.have_cbfstool:
517             cbfs_fname = os.path.join(self._indir, 'test.cbfs')
518             cbfs_util.cbfstool(cbfs_fname, 'create', '-m', 'x86', '-s',
519                                '%#x' % size)
520             cbfs_util.cbfstool(cbfs_fname, 'add-stage', '-n', 'u-boot',
521                                '-f', elf_fname)
522             self._compare_expected_cbfs(data, cbfs_fname)
523
524     def test_cbfs_raw_compress(self):
525         """Test base handling of compressing raw files"""
526         if not self.have_lz4:
527             self.skipTest('lz4 --no-frame-crc not available')
528         size = 0x140
529         cbw = CbfsWriter(size)
530         cbw.add_file_raw('u-boot', COMPRESS_DATA, None,
531                          compress=cbfs_util.COMPRESS_LZ4)
532         cbw.add_file_raw('u-boot-dtb', COMPRESS_DATA, None,
533                          compress=cbfs_util.COMPRESS_LZMA)
534         data = cbw.get_data()
535
536         cbfs = self._check_hdr(data, size)
537         self.assertIn('u-boot', cbfs.files)
538         cfile = cbfs.files['u-boot']
539         self.assertEqual(cfile.name, 'u-boot')
540         self.assertEqual(cfile.offset, 56)
541         self.assertEqual(cfile.data, COMPRESS_DATA)
542         self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW)
543         self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZ4)
544         self.assertEqual(cfile.memlen, len(COMPRESS_DATA))
545
546         self.assertIn('u-boot-dtb', cbfs.files)
547         cfile = cbfs.files['u-boot-dtb']
548         self.assertEqual(cfile.name, 'u-boot-dtb')
549         self.assertEqual(cfile.offset, 56)
550         self.assertEqual(cfile.data, COMPRESS_DATA)
551         self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW)
552         self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZMA)
553         self.assertEqual(cfile.memlen, len(COMPRESS_DATA))
554
555         cbfs_fname = self._get_expected_cbfs(size=size, compress=['lz4', 'lzma'])
556         self._compare_expected_cbfs(data, cbfs_fname)
557
558     def test_cbfs_raw_space(self):
559         """Test files with unused space in the CBFS"""
560         size = 0xf0
561         cbw = CbfsWriter(size)
562         cbw.add_file_raw('u-boot', U_BOOT_DATA)
563         cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
564         data = cbw.get_data()
565         self._check_raw(data, size)
566         cbfs_fname = self._get_expected_cbfs(size=size)
567         self._compare_expected_cbfs(data, cbfs_fname)
568
569     def test_cbfs_offset(self):
570         """Test a CBFS with files at particular offsets"""
571         size = 0x200
572         cbw = CbfsWriter(size)
573         cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40)
574         cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x140)
575
576         data = cbw.get_data()
577         cbfs = self._check_hdr(data, size)
578         self._check_uboot(cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x40,
579                           cbfs_offset=0x40)
580         self._check_dtb(cbfs, offset=0x40, cbfs_offset=0x140)
581
582         cbfs_fname = self._get_expected_cbfs(size=size, base=(0x40, 0x140))
583         self._compare_expected_cbfs(data, cbfs_fname)
584
585     def test_cbfs_invalid_file_type_header(self):
586         """Check handling of an invalid file type when outputting a header"""
587         size = 0xb0
588         cbw = CbfsWriter(size)
589         cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA, 0)
590
591         # Change the type manually before generating the CBFS, and make sure
592         # that the generator complains
593         cfile.ftype = 0xff
594         with self.assertRaises(ValueError) as e:
595             cbw.get_data()
596         self.assertIn('Unknown file type 0xff', str(e.exception))
597
598     def test_cbfs_offset_conflict(self):
599         """Test a CBFS with files that want to overlap"""
600         size = 0x200
601         cbw = CbfsWriter(size)
602         cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40)
603         cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x80)
604
605         with self.assertRaises(ValueError) as e:
606             cbw.get_data()
607         self.assertIn('No space for data before pad offset', str(e.exception))
608
609     def test_cbfs_check_offset(self):
610         """Test that we can discover the offset of a file after writing it"""
611         size = 0xb0
612         cbw = CbfsWriter(size)
613         cbw.add_file_raw('u-boot', U_BOOT_DATA)
614         cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
615         data = cbw.get_data()
616
617         cbfs = cbfs_util.CbfsReader(data)
618         self.assertEqual(0x38, cbfs.files['u-boot'].cbfs_offset)
619         self.assertEqual(0x78, cbfs.files['u-boot-dtb'].cbfs_offset)
620
621
622 if __name__ == '__main__':
623     unittest.main()