xref: /rk3399_rockchip-uboot/tools/binman/func_test.py (revision 4f44304b0bd881f79252c7b7d2fb796e31ca3b0a)
1*4f44304bSSimon Glass#
2*4f44304bSSimon Glass# Copyright (c) 2016 Google, Inc
3*4f44304bSSimon Glass# Written by Simon Glass <sjg@chromium.org>
4*4f44304bSSimon Glass#
5*4f44304bSSimon Glass# SPDX-License-Identifier:      GPL-2.0+
6*4f44304bSSimon Glass#
7*4f44304bSSimon Glass# To run a single test, change to this directory, and:
8*4f44304bSSimon Glass#
9*4f44304bSSimon Glass#    python -m unittest func_test.TestFunctional.testHelp
10*4f44304bSSimon Glass
11*4f44304bSSimon Glassfrom optparse import OptionParser
12*4f44304bSSimon Glassimport os
13*4f44304bSSimon Glassimport shutil
14*4f44304bSSimon Glassimport struct
15*4f44304bSSimon Glassimport sys
16*4f44304bSSimon Glassimport tempfile
17*4f44304bSSimon Glassimport unittest
18*4f44304bSSimon Glass
19*4f44304bSSimon Glassimport binman
20*4f44304bSSimon Glassimport cmdline
21*4f44304bSSimon Glassimport command
22*4f44304bSSimon Glassimport control
23*4f44304bSSimon Glassimport entry
24*4f44304bSSimon Glassimport fdt_select
25*4f44304bSSimon Glassimport fdt_util
26*4f44304bSSimon Glassimport tools
27*4f44304bSSimon Glassimport tout
28*4f44304bSSimon Glass
29*4f44304bSSimon Glass# Contents of test files, corresponding to different entry types
30*4f44304bSSimon GlassU_BOOT_DATA         = '1234'
31*4f44304bSSimon GlassU_BOOT_IMG_DATA     = 'img'
32*4f44304bSSimon GlassU_BOOT_SPL_DATA     = '567'
33*4f44304bSSimon GlassBLOB_DATA           = '89'
34*4f44304bSSimon GlassME_DATA             = '0abcd'
35*4f44304bSSimon GlassVGA_DATA            = 'vga'
36*4f44304bSSimon GlassU_BOOT_DTB_DATA     = 'udtb'
37*4f44304bSSimon GlassX86_START16_DATA    = 'start16'
38*4f44304bSSimon GlassU_BOOT_NODTB_DATA   = 'nodtb with microcode pointer somewhere in here'
39*4f44304bSSimon Glass
40*4f44304bSSimon Glassclass TestFunctional(unittest.TestCase):
41*4f44304bSSimon Glass    """Functional tests for binman
42*4f44304bSSimon Glass
43*4f44304bSSimon Glass    Most of these use a sample .dts file to build an image and then check
44*4f44304bSSimon Glass    that it looks correct. The sample files are in the test/ subdirectory
45*4f44304bSSimon Glass    and are numbered.
46*4f44304bSSimon Glass
47*4f44304bSSimon Glass    For each entry type a very small test file is created using fixed
48*4f44304bSSimon Glass    string contents. This makes it easy to test that things look right, and
49*4f44304bSSimon Glass    debug problems.
50*4f44304bSSimon Glass
51*4f44304bSSimon Glass    In some cases a 'real' file must be used - these are also supplied in
52*4f44304bSSimon Glass    the test/ diurectory.
53*4f44304bSSimon Glass    """
54*4f44304bSSimon Glass    @classmethod
55*4f44304bSSimon Glass    def setUpClass(self):
56*4f44304bSSimon Glass        # Handle the case where argv[0] is 'python'
57*4f44304bSSimon Glass        self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
58*4f44304bSSimon Glass        self._binman_pathname = os.path.join(self._binman_dir, 'binman')
59*4f44304bSSimon Glass
60*4f44304bSSimon Glass        # Create a temporary directory for input files
61*4f44304bSSimon Glass        self._indir = tempfile.mkdtemp(prefix='binmant.')
62*4f44304bSSimon Glass
63*4f44304bSSimon Glass        # Create some test files
64*4f44304bSSimon Glass        TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
65*4f44304bSSimon Glass        TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
66*4f44304bSSimon Glass        TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
67*4f44304bSSimon Glass        TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
68*4f44304bSSimon Glass        TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
69*4f44304bSSimon Glass        TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
70*4f44304bSSimon Glass        self._output_setup = False
71*4f44304bSSimon Glass
72*4f44304bSSimon Glass    @classmethod
73*4f44304bSSimon Glass    def tearDownClass(self):
74*4f44304bSSimon Glass        """Remove the temporary input directory and its contents"""
75*4f44304bSSimon Glass        if self._indir:
76*4f44304bSSimon Glass            shutil.rmtree(self._indir)
77*4f44304bSSimon Glass        self._indir = None
78*4f44304bSSimon Glass
79*4f44304bSSimon Glass    def setUp(self):
80*4f44304bSSimon Glass        # Enable this to turn on debugging output
81*4f44304bSSimon Glass        # tout.Init(tout.DEBUG)
82*4f44304bSSimon Glass        command.test_result = None
83*4f44304bSSimon Glass
84*4f44304bSSimon Glass    def tearDown(self):
85*4f44304bSSimon Glass        """Remove the temporary output directory"""
86*4f44304bSSimon Glass        tools._FinaliseForTest()
87*4f44304bSSimon Glass
88*4f44304bSSimon Glass    def _RunBinman(self, *args, **kwargs):
89*4f44304bSSimon Glass        """Run binman using the command line
90*4f44304bSSimon Glass
91*4f44304bSSimon Glass        Args:
92*4f44304bSSimon Glass            Arguments to pass, as a list of strings
93*4f44304bSSimon Glass            kwargs: Arguments to pass to Command.RunPipe()
94*4f44304bSSimon Glass        """
95*4f44304bSSimon Glass        result = command.RunPipe([[self._binman_pathname] + list(args)],
96*4f44304bSSimon Glass                capture=True, capture_stderr=True, raise_on_error=False)
97*4f44304bSSimon Glass        if result.return_code and kwargs.get('raise_on_error', True):
98*4f44304bSSimon Glass            raise Exception("Error running '%s': %s" % (' '.join(args),
99*4f44304bSSimon Glass                            result.stdout + result.stderr))
100*4f44304bSSimon Glass        return result
101*4f44304bSSimon Glass
102*4f44304bSSimon Glass    def _DoBinman(self, *args):
103*4f44304bSSimon Glass        """Run binman using directly (in the same process)
104*4f44304bSSimon Glass
105*4f44304bSSimon Glass        Args:
106*4f44304bSSimon Glass            Arguments to pass, as a list of strings
107*4f44304bSSimon Glass        Returns:
108*4f44304bSSimon Glass            Return value (0 for success)
109*4f44304bSSimon Glass        """
110*4f44304bSSimon Glass        (options, args) = cmdline.ParseArgs(list(args))
111*4f44304bSSimon Glass        options.pager = 'binman-invalid-pager'
112*4f44304bSSimon Glass        options.build_dir = self._indir
113*4f44304bSSimon Glass
114*4f44304bSSimon Glass        # For testing, you can force an increase in verbosity here
115*4f44304bSSimon Glass        # options.verbosity = tout.DEBUG
116*4f44304bSSimon Glass        return control.Binman(options, args)
117*4f44304bSSimon Glass
118*4f44304bSSimon Glass    def _DoTestFile(self, fname):
119*4f44304bSSimon Glass        """Run binman with a given test file
120*4f44304bSSimon Glass
121*4f44304bSSimon Glass        Args:
122*4f44304bSSimon Glass            fname: Device tree source filename to use (e.g. 05_simple.dts)
123*4f44304bSSimon Glass        """
124*4f44304bSSimon Glass        return self._DoBinman('-p', '-I', self._indir,
125*4f44304bSSimon Glass                              '-d', self.TestFile(fname))
126*4f44304bSSimon Glass
127*4f44304bSSimon Glass    def _SetupDtb(self, fname, outfile='u-boot.dtb'):
128*4f44304bSSimon Glass        if not self._output_setup:
129*4f44304bSSimon Glass            tools.PrepareOutputDir(self._indir, True)
130*4f44304bSSimon Glass            self._output_setup = True
131*4f44304bSSimon Glass        dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
132*4f44304bSSimon Glass        with open(dtb) as fd:
133*4f44304bSSimon Glass            data = fd.read()
134*4f44304bSSimon Glass            TestFunctional._MakeInputFile(outfile, data)
135*4f44304bSSimon Glass
136*4f44304bSSimon Glass    def _DoReadFile(self, fname, use_real_dtb=False):
137*4f44304bSSimon Glass        """Run binman and return the resulting image
138*4f44304bSSimon Glass
139*4f44304bSSimon Glass        This runs binman with a given test file and then reads the resulting
140*4f44304bSSimon Glass        output file. It is a shortcut function since most tests need to do
141*4f44304bSSimon Glass        these steps.
142*4f44304bSSimon Glass
143*4f44304bSSimon Glass        Raises an assertion failure if binman returns a non-zero exit code.
144*4f44304bSSimon Glass
145*4f44304bSSimon Glass        Args:
146*4f44304bSSimon Glass            fname: Device tree source filename to use (e.g. 05_simple.dts)
147*4f44304bSSimon Glass            use_real_dtb: True to use the test file as the contents of
148*4f44304bSSimon Glass                the u-boot-dtb entry. Normally this is not needed and the
149*4f44304bSSimon Glass                test contents (the U_BOOT_DTB_DATA string) can be used.
150*4f44304bSSimon Glass                But in some test we need the real contents.
151*4f44304bSSimon Glass        """
152*4f44304bSSimon Glass        # Use the compiled test file as the u-boot-dtb input
153*4f44304bSSimon Glass        if use_real_dtb:
154*4f44304bSSimon Glass            self._SetupDtb(fname)
155*4f44304bSSimon Glass
156*4f44304bSSimon Glass        try:
157*4f44304bSSimon Glass            retcode = self._DoTestFile(fname)
158*4f44304bSSimon Glass            self.assertEqual(0, retcode)
159*4f44304bSSimon Glass
160*4f44304bSSimon Glass            # Find the (only) image, read it and return its contents
161*4f44304bSSimon Glass            image = control.images['image']
162*4f44304bSSimon Glass            fname = tools.GetOutputFilename('image.bin')
163*4f44304bSSimon Glass            self.assertTrue(os.path.exists(fname))
164*4f44304bSSimon Glass            with open(fname) as fd:
165*4f44304bSSimon Glass                return fd.read()
166*4f44304bSSimon Glass        finally:
167*4f44304bSSimon Glass            # Put the test file back
168*4f44304bSSimon Glass            if use_real_dtb:
169*4f44304bSSimon Glass                TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
170*4f44304bSSimon Glass
171*4f44304bSSimon Glass    @classmethod
172*4f44304bSSimon Glass    def _MakeInputFile(self, fname, contents):
173*4f44304bSSimon Glass        """Create a new test input file, creating directories as needed
174*4f44304bSSimon Glass
175*4f44304bSSimon Glass        Args:
176*4f44304bSSimon Glass            fname: Filenaem to create
177*4f44304bSSimon Glass            contents: File contents to write in to the file
178*4f44304bSSimon Glass        Returns:
179*4f44304bSSimon Glass            Full pathname of file created
180*4f44304bSSimon Glass        """
181*4f44304bSSimon Glass        pathname = os.path.join(self._indir, fname)
182*4f44304bSSimon Glass        dirname = os.path.dirname(pathname)
183*4f44304bSSimon Glass        if dirname and not os.path.exists(dirname):
184*4f44304bSSimon Glass            os.makedirs(dirname)
185*4f44304bSSimon Glass        with open(pathname, 'wb') as fd:
186*4f44304bSSimon Glass            fd.write(contents)
187*4f44304bSSimon Glass        return pathname
188*4f44304bSSimon Glass
189*4f44304bSSimon Glass    @classmethod
190*4f44304bSSimon Glass    def TestFile(self, fname):
191*4f44304bSSimon Glass        return os.path.join(self._binman_dir, 'test', fname)
192*4f44304bSSimon Glass
193*4f44304bSSimon Glass    def AssertInList(self, grep_list, target):
194*4f44304bSSimon Glass        """Assert that at least one of a list of things is in a target
195*4f44304bSSimon Glass
196*4f44304bSSimon Glass        Args:
197*4f44304bSSimon Glass            grep_list: List of strings to check
198*4f44304bSSimon Glass            target: Target string
199*4f44304bSSimon Glass        """
200*4f44304bSSimon Glass        for grep in grep_list:
201*4f44304bSSimon Glass            if grep in target:
202*4f44304bSSimon Glass                return
203*4f44304bSSimon Glass        self.fail("Error: '%' not found in '%s'" % (grep_list, target))
204*4f44304bSSimon Glass
205*4f44304bSSimon Glass    def CheckNoGaps(self, entries):
206*4f44304bSSimon Glass        """Check that all entries fit together without gaps
207*4f44304bSSimon Glass
208*4f44304bSSimon Glass        Args:
209*4f44304bSSimon Glass            entries: List of entries to check
210*4f44304bSSimon Glass        """
211*4f44304bSSimon Glass        pos = 0
212*4f44304bSSimon Glass        for entry in entries.values():
213*4f44304bSSimon Glass            self.assertEqual(pos, entry.pos)
214*4f44304bSSimon Glass            pos += entry.size
215*4f44304bSSimon Glass
216*4f44304bSSimon Glass    def testRun(self):
217*4f44304bSSimon Glass        """Test a basic run with valid args"""
218*4f44304bSSimon Glass        result = self._RunBinman('-h')
219*4f44304bSSimon Glass
220*4f44304bSSimon Glass    def testFullHelp(self):
221*4f44304bSSimon Glass        """Test that the full help is displayed with -H"""
222*4f44304bSSimon Glass        result = self._RunBinman('-H')
223*4f44304bSSimon Glass        help_file = os.path.join(self._binman_dir, 'README')
224*4f44304bSSimon Glass        self.assertEqual(len(result.stdout), os.path.getsize(help_file))
225*4f44304bSSimon Glass        self.assertEqual(0, len(result.stderr))
226*4f44304bSSimon Glass        self.assertEqual(0, result.return_code)
227*4f44304bSSimon Glass
228*4f44304bSSimon Glass    def testFullHelpInternal(self):
229*4f44304bSSimon Glass        """Test that the full help is displayed with -H"""
230*4f44304bSSimon Glass        try:
231*4f44304bSSimon Glass            command.test_result = command.CommandResult()
232*4f44304bSSimon Glass            result = self._DoBinman('-H')
233*4f44304bSSimon Glass            help_file = os.path.join(self._binman_dir, 'README')
234*4f44304bSSimon Glass        finally:
235*4f44304bSSimon Glass            command.test_result = None
236*4f44304bSSimon Glass
237*4f44304bSSimon Glass    def testHelp(self):
238*4f44304bSSimon Glass        """Test that the basic help is displayed with -h"""
239*4f44304bSSimon Glass        result = self._RunBinman('-h')
240*4f44304bSSimon Glass        self.assertTrue(len(result.stdout) > 200)
241*4f44304bSSimon Glass        self.assertEqual(0, len(result.stderr))
242*4f44304bSSimon Glass        self.assertEqual(0, result.return_code)
243*4f44304bSSimon Glass
244*4f44304bSSimon Glass    # Not yet available.
245*4f44304bSSimon Glass    def testBoard(self):
246*4f44304bSSimon Glass        """Test that we can run it with a specific board"""
247*4f44304bSSimon Glass        self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
248*4f44304bSSimon Glass        TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
249*4f44304bSSimon Glass        result = self._DoBinman('-b', 'sandbox')
250*4f44304bSSimon Glass        self.assertEqual(0, result)
251*4f44304bSSimon Glass
252*4f44304bSSimon Glass    def testNeedBoard(self):
253*4f44304bSSimon Glass        """Test that we get an error when no board ius supplied"""
254*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
255*4f44304bSSimon Glass            result = self._DoBinman()
256*4f44304bSSimon Glass        self.assertIn("Must provide a board to process (use -b <board>)",
257*4f44304bSSimon Glass                str(e.exception))
258*4f44304bSSimon Glass
259*4f44304bSSimon Glass    def testMissingDt(self):
260*4f44304bSSimon Glass        """Test that an invalid device tree file generates an error"""
261*4f44304bSSimon Glass        with self.assertRaises(Exception) as e:
262*4f44304bSSimon Glass            self._RunBinman('-d', 'missing_file')
263*4f44304bSSimon Glass        # We get one error from libfdt, and a different one from fdtget.
264*4f44304bSSimon Glass        self.AssertInList(["Couldn't open blob from 'missing_file'",
265*4f44304bSSimon Glass                           'No such file or directory'], str(e.exception))
266*4f44304bSSimon Glass
267*4f44304bSSimon Glass    def testBrokenDt(self):
268*4f44304bSSimon Glass        """Test that an invalid device tree source file generates an error
269*4f44304bSSimon Glass
270*4f44304bSSimon Glass        Since this is a source file it should be compiled and the error
271*4f44304bSSimon Glass        will come from the device-tree compiler (dtc).
272*4f44304bSSimon Glass        """
273*4f44304bSSimon Glass        with self.assertRaises(Exception) as e:
274*4f44304bSSimon Glass            self._RunBinman('-d', self.TestFile('01_invalid.dts'))
275*4f44304bSSimon Glass        self.assertIn("FATAL ERROR: Unable to parse input tree",
276*4f44304bSSimon Glass                str(e.exception))
277*4f44304bSSimon Glass
278*4f44304bSSimon Glass    def testMissingNode(self):
279*4f44304bSSimon Glass        """Test that a device tree without a 'binman' node generates an error"""
280*4f44304bSSimon Glass        with self.assertRaises(Exception) as e:
281*4f44304bSSimon Glass            self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
282*4f44304bSSimon Glass        self.assertIn("does not have a 'binman' node", str(e.exception))
283*4f44304bSSimon Glass
284*4f44304bSSimon Glass    def testEmpty(self):
285*4f44304bSSimon Glass        """Test that an empty binman node works OK (i.e. does nothing)"""
286*4f44304bSSimon Glass        result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
287*4f44304bSSimon Glass        self.assertEqual(0, len(result.stderr))
288*4f44304bSSimon Glass        self.assertEqual(0, result.return_code)
289*4f44304bSSimon Glass
290*4f44304bSSimon Glass    def testInvalidEntry(self):
291*4f44304bSSimon Glass        """Test that an invalid entry is flagged"""
292*4f44304bSSimon Glass        with self.assertRaises(Exception) as e:
293*4f44304bSSimon Glass            result = self._RunBinman('-d',
294*4f44304bSSimon Glass                                     self.TestFile('04_invalid_entry.dts'))
295*4f44304bSSimon Glass        #print e.exception
296*4f44304bSSimon Glass        self.assertIn("Unknown entry type 'not-a-valid-type' in node "
297*4f44304bSSimon Glass                "'/binman/not-a-valid-type'", str(e.exception))
298*4f44304bSSimon Glass
299*4f44304bSSimon Glass    def testSimple(self):
300*4f44304bSSimon Glass        """Test a simple binman with a single file"""
301*4f44304bSSimon Glass        data = self._DoReadFile('05_simple.dts')
302*4f44304bSSimon Glass        self.assertEqual(U_BOOT_DATA, data)
303*4f44304bSSimon Glass
304*4f44304bSSimon Glass    def testDual(self):
305*4f44304bSSimon Glass        """Test that we can handle creating two images
306*4f44304bSSimon Glass
307*4f44304bSSimon Glass        This also tests image padding.
308*4f44304bSSimon Glass        """
309*4f44304bSSimon Glass        retcode = self._DoTestFile('06_dual_image.dts')
310*4f44304bSSimon Glass        self.assertEqual(0, retcode)
311*4f44304bSSimon Glass
312*4f44304bSSimon Glass        image = control.images['image1']
313*4f44304bSSimon Glass        self.assertEqual(len(U_BOOT_DATA), image._size)
314*4f44304bSSimon Glass        fname = tools.GetOutputFilename('image1.bin')
315*4f44304bSSimon Glass        self.assertTrue(os.path.exists(fname))
316*4f44304bSSimon Glass        with open(fname) as fd:
317*4f44304bSSimon Glass            data = fd.read()
318*4f44304bSSimon Glass            self.assertEqual(U_BOOT_DATA, data)
319*4f44304bSSimon Glass
320*4f44304bSSimon Glass        image = control.images['image2']
321*4f44304bSSimon Glass        self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
322*4f44304bSSimon Glass        fname = tools.GetOutputFilename('image2.bin')
323*4f44304bSSimon Glass        self.assertTrue(os.path.exists(fname))
324*4f44304bSSimon Glass        with open(fname) as fd:
325*4f44304bSSimon Glass            data = fd.read()
326*4f44304bSSimon Glass            self.assertEqual(U_BOOT_DATA, data[3:7])
327*4f44304bSSimon Glass            self.assertEqual(chr(0) * 3, data[:3])
328*4f44304bSSimon Glass            self.assertEqual(chr(0) * 5, data[7:])
329*4f44304bSSimon Glass
330*4f44304bSSimon Glass    def testBadAlign(self):
331*4f44304bSSimon Glass        """Test that an invalid alignment value is detected"""
332*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
333*4f44304bSSimon Glass            self._DoTestFile('07_bad_align.dts')
334*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
335*4f44304bSSimon Glass                      "of two", str(e.exception))
336*4f44304bSSimon Glass
337*4f44304bSSimon Glass    def testPackSimple(self):
338*4f44304bSSimon Glass        """Test that packing works as expected"""
339*4f44304bSSimon Glass        retcode = self._DoTestFile('08_pack.dts')
340*4f44304bSSimon Glass        self.assertEqual(0, retcode)
341*4f44304bSSimon Glass        self.assertIn('image', control.images)
342*4f44304bSSimon Glass        image = control.images['image']
343*4f44304bSSimon Glass        entries = image._entries
344*4f44304bSSimon Glass        self.assertEqual(5, len(entries))
345*4f44304bSSimon Glass
346*4f44304bSSimon Glass        # First u-boot
347*4f44304bSSimon Glass        self.assertIn('u-boot', entries)
348*4f44304bSSimon Glass        entry = entries['u-boot']
349*4f44304bSSimon Glass        self.assertEqual(0, entry.pos)
350*4f44304bSSimon Glass        self.assertEqual(len(U_BOOT_DATA), entry.size)
351*4f44304bSSimon Glass
352*4f44304bSSimon Glass        # Second u-boot, aligned to 16-byte boundary
353*4f44304bSSimon Glass        self.assertIn('u-boot-align', entries)
354*4f44304bSSimon Glass        entry = entries['u-boot-align']
355*4f44304bSSimon Glass        self.assertEqual(16, entry.pos)
356*4f44304bSSimon Glass        self.assertEqual(len(U_BOOT_DATA), entry.size)
357*4f44304bSSimon Glass
358*4f44304bSSimon Glass        # Third u-boot, size 23 bytes
359*4f44304bSSimon Glass        self.assertIn('u-boot-size', entries)
360*4f44304bSSimon Glass        entry = entries['u-boot-size']
361*4f44304bSSimon Glass        self.assertEqual(20, entry.pos)
362*4f44304bSSimon Glass        self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
363*4f44304bSSimon Glass        self.assertEqual(23, entry.size)
364*4f44304bSSimon Glass
365*4f44304bSSimon Glass        # Fourth u-boot, placed immediate after the above
366*4f44304bSSimon Glass        self.assertIn('u-boot-next', entries)
367*4f44304bSSimon Glass        entry = entries['u-boot-next']
368*4f44304bSSimon Glass        self.assertEqual(43, entry.pos)
369*4f44304bSSimon Glass        self.assertEqual(len(U_BOOT_DATA), entry.size)
370*4f44304bSSimon Glass
371*4f44304bSSimon Glass        # Fifth u-boot, placed at a fixed position
372*4f44304bSSimon Glass        self.assertIn('u-boot-fixed', entries)
373*4f44304bSSimon Glass        entry = entries['u-boot-fixed']
374*4f44304bSSimon Glass        self.assertEqual(61, entry.pos)
375*4f44304bSSimon Glass        self.assertEqual(len(U_BOOT_DATA), entry.size)
376*4f44304bSSimon Glass
377*4f44304bSSimon Glass        self.assertEqual(65, image._size)
378*4f44304bSSimon Glass
379*4f44304bSSimon Glass    def testPackExtra(self):
380*4f44304bSSimon Glass        """Test that extra packing feature works as expected"""
381*4f44304bSSimon Glass        retcode = self._DoTestFile('09_pack_extra.dts')
382*4f44304bSSimon Glass
383*4f44304bSSimon Glass        self.assertEqual(0, retcode)
384*4f44304bSSimon Glass        self.assertIn('image', control.images)
385*4f44304bSSimon Glass        image = control.images['image']
386*4f44304bSSimon Glass        entries = image._entries
387*4f44304bSSimon Glass        self.assertEqual(5, len(entries))
388*4f44304bSSimon Glass
389*4f44304bSSimon Glass        # First u-boot with padding before and after
390*4f44304bSSimon Glass        self.assertIn('u-boot', entries)
391*4f44304bSSimon Glass        entry = entries['u-boot']
392*4f44304bSSimon Glass        self.assertEqual(0, entry.pos)
393*4f44304bSSimon Glass        self.assertEqual(3, entry.pad_before)
394*4f44304bSSimon Glass        self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
395*4f44304bSSimon Glass
396*4f44304bSSimon Glass        # Second u-boot has an aligned size, but it has no effect
397*4f44304bSSimon Glass        self.assertIn('u-boot-align-size-nop', entries)
398*4f44304bSSimon Glass        entry = entries['u-boot-align-size-nop']
399*4f44304bSSimon Glass        self.assertEqual(12, entry.pos)
400*4f44304bSSimon Glass        self.assertEqual(4, entry.size)
401*4f44304bSSimon Glass
402*4f44304bSSimon Glass        # Third u-boot has an aligned size too
403*4f44304bSSimon Glass        self.assertIn('u-boot-align-size', entries)
404*4f44304bSSimon Glass        entry = entries['u-boot-align-size']
405*4f44304bSSimon Glass        self.assertEqual(16, entry.pos)
406*4f44304bSSimon Glass        self.assertEqual(32, entry.size)
407*4f44304bSSimon Glass
408*4f44304bSSimon Glass        # Fourth u-boot has an aligned end
409*4f44304bSSimon Glass        self.assertIn('u-boot-align-end', entries)
410*4f44304bSSimon Glass        entry = entries['u-boot-align-end']
411*4f44304bSSimon Glass        self.assertEqual(48, entry.pos)
412*4f44304bSSimon Glass        self.assertEqual(16, entry.size)
413*4f44304bSSimon Glass
414*4f44304bSSimon Glass        # Fifth u-boot immediately afterwards
415*4f44304bSSimon Glass        self.assertIn('u-boot-align-both', entries)
416*4f44304bSSimon Glass        entry = entries['u-boot-align-both']
417*4f44304bSSimon Glass        self.assertEqual(64, entry.pos)
418*4f44304bSSimon Glass        self.assertEqual(64, entry.size)
419*4f44304bSSimon Glass
420*4f44304bSSimon Glass        self.CheckNoGaps(entries)
421*4f44304bSSimon Glass        self.assertEqual(128, image._size)
422*4f44304bSSimon Glass
423*4f44304bSSimon Glass    def testPackAlignPowerOf2(self):
424*4f44304bSSimon Glass        """Test that invalid entry alignment is detected"""
425*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
426*4f44304bSSimon Glass            self._DoTestFile('10_pack_align_power2.dts')
427*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
428*4f44304bSSimon Glass                      "of two", str(e.exception))
429*4f44304bSSimon Glass
430*4f44304bSSimon Glass    def testPackAlignSizePowerOf2(self):
431*4f44304bSSimon Glass        """Test that invalid entry size alignment is detected"""
432*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
433*4f44304bSSimon Glass            self._DoTestFile('11_pack_align_size_power2.dts')
434*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
435*4f44304bSSimon Glass                      "power of two", str(e.exception))
436*4f44304bSSimon Glass
437*4f44304bSSimon Glass    def testPackInvalidAlign(self):
438*4f44304bSSimon Glass        """Test detection of an position that does not match its alignment"""
439*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
440*4f44304bSSimon Glass            self._DoTestFile('12_pack_inv_align.dts')
441*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot': Position 0x5 (5) does not match "
442*4f44304bSSimon Glass                      "align 0x4 (4)", str(e.exception))
443*4f44304bSSimon Glass
444*4f44304bSSimon Glass    def testPackInvalidSizeAlign(self):
445*4f44304bSSimon Glass        """Test that invalid entry size alignment is detected"""
446*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
447*4f44304bSSimon Glass            self._DoTestFile('13_pack_inv_size_align.dts')
448*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
449*4f44304bSSimon Glass                      "align-size 0x4 (4)", str(e.exception))
450*4f44304bSSimon Glass
451*4f44304bSSimon Glass    def testPackOverlap(self):
452*4f44304bSSimon Glass        """Test that overlapping regions are detected"""
453*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
454*4f44304bSSimon Glass            self._DoTestFile('14_pack_overlap.dts')
455*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot-align': Position 0x3 (3) overlaps "
456*4f44304bSSimon Glass                      "with previous entry '/binman/u-boot' ending at 0x4 (4)",
457*4f44304bSSimon Glass                      str(e.exception))
458*4f44304bSSimon Glass
459*4f44304bSSimon Glass    def testPackEntryOverflow(self):
460*4f44304bSSimon Glass        """Test that entries that overflow their size are detected"""
461*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
462*4f44304bSSimon Glass            self._DoTestFile('15_pack_overflow.dts')
463*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
464*4f44304bSSimon Glass                      "but entry size is 0x3 (3)", str(e.exception))
465*4f44304bSSimon Glass
466*4f44304bSSimon Glass    def testPackImageOverflow(self):
467*4f44304bSSimon Glass        """Test that entries which overflow the image size are detected"""
468*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
469*4f44304bSSimon Glass            self._DoTestFile('16_pack_image_overflow.dts')
470*4f44304bSSimon Glass        self.assertIn("Image '/binman': contents size 0x4 (4) exceeds image "
471*4f44304bSSimon Glass                      "size 0x3 (3)", str(e.exception))
472*4f44304bSSimon Glass
473*4f44304bSSimon Glass    def testPackImageSize(self):
474*4f44304bSSimon Glass        """Test that the image size can be set"""
475*4f44304bSSimon Glass        retcode = self._DoTestFile('17_pack_image_size.dts')
476*4f44304bSSimon Glass        self.assertEqual(0, retcode)
477*4f44304bSSimon Glass        self.assertIn('image', control.images)
478*4f44304bSSimon Glass        image = control.images['image']
479*4f44304bSSimon Glass        self.assertEqual(7, image._size)
480*4f44304bSSimon Glass
481*4f44304bSSimon Glass    def testPackImageSizeAlign(self):
482*4f44304bSSimon Glass        """Test that image size alignemnt works as expected"""
483*4f44304bSSimon Glass        retcode = self._DoTestFile('18_pack_image_align.dts')
484*4f44304bSSimon Glass        self.assertEqual(0, retcode)
485*4f44304bSSimon Glass        self.assertIn('image', control.images)
486*4f44304bSSimon Glass        image = control.images['image']
487*4f44304bSSimon Glass        self.assertEqual(16, image._size)
488*4f44304bSSimon Glass
489*4f44304bSSimon Glass    def testPackInvalidImageAlign(self):
490*4f44304bSSimon Glass        """Test that invalid image alignment is detected"""
491*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
492*4f44304bSSimon Glass            self._DoTestFile('19_pack_inv_image_align.dts')
493*4f44304bSSimon Glass        self.assertIn("Image '/binman': Size 0x7 (7) does not match "
494*4f44304bSSimon Glass                      "align-size 0x8 (8)", str(e.exception))
495*4f44304bSSimon Glass
496*4f44304bSSimon Glass    def testPackAlignPowerOf2(self):
497*4f44304bSSimon Glass        """Test that invalid image alignment is detected"""
498*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
499*4f44304bSSimon Glass            self._DoTestFile('20_pack_inv_image_align_power2.dts')
500*4f44304bSSimon Glass        self.assertIn("Image '/binman': Alignment size 131 must be a power of "
501*4f44304bSSimon Glass                      "two", str(e.exception))
502*4f44304bSSimon Glass
503*4f44304bSSimon Glass    def testImagePadByte(self):
504*4f44304bSSimon Glass        """Test that the image pad byte can be specified"""
505*4f44304bSSimon Glass        data = self._DoReadFile('21_image_pad.dts')
506*4f44304bSSimon Glass        self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data)
507*4f44304bSSimon Glass
508*4f44304bSSimon Glass    def testImageName(self):
509*4f44304bSSimon Glass        """Test that image files can be named"""
510*4f44304bSSimon Glass        retcode = self._DoTestFile('22_image_name.dts')
511*4f44304bSSimon Glass        self.assertEqual(0, retcode)
512*4f44304bSSimon Glass        image = control.images['image1']
513*4f44304bSSimon Glass        fname = tools.GetOutputFilename('test-name')
514*4f44304bSSimon Glass        self.assertTrue(os.path.exists(fname))
515*4f44304bSSimon Glass
516*4f44304bSSimon Glass        image = control.images['image2']
517*4f44304bSSimon Glass        fname = tools.GetOutputFilename('test-name.xx')
518*4f44304bSSimon Glass        self.assertTrue(os.path.exists(fname))
519*4f44304bSSimon Glass
520*4f44304bSSimon Glass    def testBlobFilename(self):
521*4f44304bSSimon Glass        """Test that generic blobs can be provided by filename"""
522*4f44304bSSimon Glass        data = self._DoReadFile('23_blob.dts')
523*4f44304bSSimon Glass        self.assertEqual(BLOB_DATA, data)
524*4f44304bSSimon Glass
525*4f44304bSSimon Glass    def testPackSorted(self):
526*4f44304bSSimon Glass        """Test that entries can be sorted"""
527*4f44304bSSimon Glass        data = self._DoReadFile('24_sorted.dts')
528*4f44304bSSimon Glass        self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 +
529*4f44304bSSimon Glass                         U_BOOT_DATA, data)
530*4f44304bSSimon Glass
531*4f44304bSSimon Glass    def testPackZeroPosition(self):
532*4f44304bSSimon Glass        """Test that an entry at position 0 is not given a new position"""
533*4f44304bSSimon Glass        with self.assertRaises(ValueError) as e:
534*4f44304bSSimon Glass            self._DoTestFile('25_pack_zero_size.dts')
535*4f44304bSSimon Glass        self.assertIn("Node '/binman/u-boot-spl': Position 0x0 (0) overlaps "
536*4f44304bSSimon Glass                      "with previous entry '/binman/u-boot' ending at 0x4 (4)",
537*4f44304bSSimon Glass                      str(e.exception))
538*4f44304bSSimon Glass
539*4f44304bSSimon Glass    def testPackUbootDtb(self):
540*4f44304bSSimon Glass        """Test that a device tree can be added to U-Boot"""
541*4f44304bSSimon Glass        data = self._DoReadFile('26_pack_u_boot_dtb.dts')
542*4f44304bSSimon Glass        self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
543