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