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