1# SPDX-License-Identifier: GPL-2.0+ 2# Copyright (c) 2012 The Chromium OS Authors. 3# 4 5"""Tests for the dtb_platdata module 6 7This includes unit tests for some functions and functional tests for the dtoc 8tool. 9""" 10 11import collections 12import os 13import struct 14import unittest 15 16import dtb_platdata 17from dtb_platdata import conv_name_to_c 18from dtb_platdata import get_compat_name 19from dtb_platdata import get_value 20from dtb_platdata import tab_to 21import fdt 22import fdt_util 23import test_util 24import tools 25 26our_path = os.path.dirname(os.path.realpath(__file__)) 27 28 29HEADER = '''/* 30 * DO NOT MODIFY 31 * 32 * This file was generated by dtoc from a .dtb (device tree binary) file. 33 */ 34 35#include <stdbool.h> 36#include <linux/libfdt.h>''' 37 38C_HEADER = '''/* 39 * DO NOT MODIFY 40 * 41 * This file was generated by dtoc from a .dtb (device tree binary) file. 42 */ 43 44#include <common.h> 45#include <dm.h> 46#include <dt-structs.h> 47''' 48 49 50 51def get_dtb_file(dts_fname, capture_stderr=False): 52 """Compile a .dts file to a .dtb 53 54 Args: 55 dts_fname: Filename of .dts file in the current directory 56 capture_stderr: True to capture and discard stderr output 57 58 Returns: 59 Filename of compiled file in output directory 60 """ 61 return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname), 62 capture_stderr=capture_stderr) 63 64 65class TestDtoc(unittest.TestCase): 66 """Tests for dtoc""" 67 @classmethod 68 def setUpClass(cls): 69 tools.PrepareOutputDir(None) 70 71 @classmethod 72 def tearDownClass(cls): 73 tools._RemoveOutputDir() 74 75 def _WritePythonString(self, fname, data): 76 """Write a string with tabs expanded as done in this Python file 77 78 Args: 79 fname: Filename to write to 80 data: Raw string to convert 81 """ 82 data = data.replace('\t', '\\t') 83 with open(fname, 'w') as fd: 84 fd.write(data) 85 86 def _CheckStrings(self, expected, actual): 87 """Check that a string matches its expected value 88 89 If the strings do not match, they are written to the /tmp directory in 90 the same Python format as is used here in the test. This allows for 91 easy comparison and update of the tests. 92 93 Args: 94 expected: Expected string 95 actual: Actual string 96 """ 97 if expected != actual: 98 self._WritePythonString('/tmp/binman.expected', expected) 99 self._WritePythonString('/tmp/binman.actual', actual) 100 print 'Failures written to /tmp/binman.{expected,actual}' 101 self.assertEquals(expected, actual) 102 103 def test_name(self): 104 """Test conversion of device tree names to C identifiers""" 105 self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12')) 106 self.assertEqual('vendor_clock_frequency', 107 conv_name_to_c('vendor,clock-frequency')) 108 self.assertEqual('rockchip_rk3399_sdhci_5_1', 109 conv_name_to_c('rockchip,rk3399-sdhci-5.1')) 110 111 def test_tab_to(self): 112 """Test operation of tab_to() function""" 113 self.assertEqual('fred ', tab_to(0, 'fred')) 114 self.assertEqual('fred\t', tab_to(1, 'fred')) 115 self.assertEqual('fred was here ', tab_to(1, 'fred was here')) 116 self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here')) 117 self.assertEqual('exactly8 ', tab_to(1, 'exactly8')) 118 self.assertEqual('exactly8\t', tab_to(2, 'exactly8')) 119 120 def test_get_value(self): 121 """Test operation of get_value() function""" 122 self.assertEqual('0x45', 123 get_value(fdt.TYPE_INT, struct.pack('>I', 0x45))) 124 self.assertEqual('0x45', 125 get_value(fdt.TYPE_BYTE, struct.pack('<I', 0x45))) 126 self.assertEqual('0x0', 127 get_value(fdt.TYPE_BYTE, struct.pack('>I', 0x45))) 128 self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test')) 129 self.assertEqual('true', get_value(fdt.TYPE_BOOL, None)) 130 131 def test_get_compat_name(self): 132 """Test operation of get_compat_name() function""" 133 Prop = collections.namedtuple('Prop', ['value']) 134 Node = collections.namedtuple('Node', ['props']) 135 136 prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1']) 137 node = Node({'compatible': prop}) 138 self.assertEqual(('rockchip_rk3399_sdhci_5_1', ['arasan_sdhci_5_1']), 139 get_compat_name(node)) 140 141 prop = Prop(['rockchip,rk3399-sdhci-5.1']) 142 node = Node({'compatible': prop}) 143 self.assertEqual(('rockchip_rk3399_sdhci_5_1', []), 144 get_compat_name(node)) 145 146 prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third']) 147 node = Node({'compatible': prop}) 148 self.assertEqual(('rockchip_rk3399_sdhci_5_1', 149 ['arasan_sdhci_5_1', 'third']), 150 get_compat_name(node)) 151 152 def test_empty_file(self): 153 """Test output from a device tree file with no nodes""" 154 dtb_file = get_dtb_file('dtoc_test_empty.dts') 155 output = tools.GetOutputFilename('output') 156 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 157 with open(output) as infile: 158 lines = infile.read().splitlines() 159 self.assertEqual(HEADER.splitlines(), lines) 160 161 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 162 with open(output) as infile: 163 lines = infile.read().splitlines() 164 self.assertEqual(C_HEADER.splitlines() + [''], lines) 165 166 def test_simple(self): 167 """Test output from some simple nodes with various types of data""" 168 dtb_file = get_dtb_file('dtoc_test_simple.dts') 169 output = tools.GetOutputFilename('output') 170 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 171 with open(output) as infile: 172 data = infile.read() 173 self._CheckStrings(HEADER + ''' 174struct dtd_sandbox_i2c_test { 175}; 176struct dtd_sandbox_pmic_test { 177\tbool\t\tlow_power; 178\tfdt64_t\t\treg[2]; 179}; 180struct dtd_sandbox_spl_test { 181\tbool\t\tboolval; 182\tunsigned char\tbytearray[3]; 183\tunsigned char\tbyteval; 184\tfdt32_t\t\tintarray[4]; 185\tfdt32_t\t\tintval; 186\tunsigned char\tlongbytearray[9]; 187\tunsigned char\tnotstring[5]; 188\tconst char *\tstringarray[3]; 189\tconst char *\tstringval; 190}; 191struct dtd_sandbox_spl_test_2 { 192}; 193''', data) 194 195 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 196 with open(output) as infile: 197 data = infile.read() 198 self._CheckStrings(C_HEADER + ''' 199static struct dtd_sandbox_spl_test dtv_spl_test = { 200\t.bytearray\t\t= {0x6, 0x0, 0x0}, 201\t.byteval\t\t= 0x5, 202\t.intval\t\t\t= 0x1, 203\t.notstring\t\t= {0x20, 0x21, 0x22, 0x10, 0x0}, 204\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 205\t\t0x11}, 206\t.stringval\t\t= "message", 207\t.boolval\t\t= true, 208\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0}, 209\t.stringarray\t\t= {"multi-word", "message", ""}, 210}; 211U_BOOT_DEVICE(spl_test) = { 212\t.name\t\t= "sandbox_spl_test", 213\t.platdata\t= &dtv_spl_test, 214\t.platdata_size\t= sizeof(dtv_spl_test), 215}; 216 217static struct dtd_sandbox_spl_test dtv_spl_test2 = { 218\t.bytearray\t\t= {0x1, 0x23, 0x34}, 219\t.byteval\t\t= 0x8, 220\t.intval\t\t\t= 0x3, 221\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 222\t\t0x0}, 223\t.stringval\t\t= "message2", 224\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0}, 225\t.stringarray\t\t= {"another", "multi-word", "message"}, 226}; 227U_BOOT_DEVICE(spl_test2) = { 228\t.name\t\t= "sandbox_spl_test", 229\t.platdata\t= &dtv_spl_test2, 230\t.platdata_size\t= sizeof(dtv_spl_test2), 231}; 232 233static struct dtd_sandbox_spl_test dtv_spl_test3 = { 234\t.stringarray\t\t= {"one", "", ""}, 235}; 236U_BOOT_DEVICE(spl_test3) = { 237\t.name\t\t= "sandbox_spl_test", 238\t.platdata\t= &dtv_spl_test3, 239\t.platdata_size\t= sizeof(dtv_spl_test3), 240}; 241 242static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = { 243}; 244U_BOOT_DEVICE(spl_test4) = { 245\t.name\t\t= "sandbox_spl_test_2", 246\t.platdata\t= &dtv_spl_test4, 247\t.platdata_size\t= sizeof(dtv_spl_test4), 248}; 249 250static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = { 251}; 252U_BOOT_DEVICE(i2c_at_0) = { 253\t.name\t\t= "sandbox_i2c_test", 254\t.platdata\t= &dtv_i2c_at_0, 255\t.platdata_size\t= sizeof(dtv_i2c_at_0), 256}; 257 258static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = { 259\t.low_power\t\t= true, 260\t.reg\t\t\t= {0x9, 0x0}, 261}; 262U_BOOT_DEVICE(pmic_at_9) = { 263\t.name\t\t= "sandbox_pmic_test", 264\t.platdata\t= &dtv_pmic_at_9, 265\t.platdata_size\t= sizeof(dtv_pmic_at_9), 266}; 267 268''', data) 269 270 def test_phandle(self): 271 """Test output from a node containing a phandle reference""" 272 dtb_file = get_dtb_file('dtoc_test_phandle.dts') 273 output = tools.GetOutputFilename('output') 274 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 275 with open(output) as infile: 276 data = infile.read() 277 self._CheckStrings(HEADER + ''' 278struct dtd_source { 279\tstruct phandle_2_arg clocks[4]; 280}; 281struct dtd_target { 282\tfdt32_t\t\tintval; 283}; 284''', data) 285 286 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 287 with open(output) as infile: 288 data = infile.read() 289 self._CheckStrings(C_HEADER + ''' 290static struct dtd_target dtv_phandle_target = { 291\t.intval\t\t\t= 0x0, 292}; 293U_BOOT_DEVICE(phandle_target) = { 294\t.name\t\t= "target", 295\t.platdata\t= &dtv_phandle_target, 296\t.platdata_size\t= sizeof(dtv_phandle_target), 297}; 298 299static struct dtd_target dtv_phandle2_target = { 300\t.intval\t\t\t= 0x1, 301}; 302U_BOOT_DEVICE(phandle2_target) = { 303\t.name\t\t= "target", 304\t.platdata\t= &dtv_phandle2_target, 305\t.platdata_size\t= sizeof(dtv_phandle2_target), 306}; 307 308static struct dtd_target dtv_phandle3_target = { 309\t.intval\t\t\t= 0x2, 310}; 311U_BOOT_DEVICE(phandle3_target) = { 312\t.name\t\t= "target", 313\t.platdata\t= &dtv_phandle3_target, 314\t.platdata_size\t= sizeof(dtv_phandle3_target), 315}; 316 317static struct dtd_source dtv_phandle_source = { 318\t.clocks\t\t\t= { 319\t\t\t{&dtv_phandle_target, {}}, 320\t\t\t{&dtv_phandle2_target, {11}}, 321\t\t\t{&dtv_phandle3_target, {12, 13}}, 322\t\t\t{&dtv_phandle_target, {}},}, 323}; 324U_BOOT_DEVICE(phandle_source) = { 325\t.name\t\t= "source", 326\t.platdata\t= &dtv_phandle_source, 327\t.platdata_size\t= sizeof(dtv_phandle_source), 328}; 329 330static struct dtd_source dtv_phandle_source2 = { 331\t.clocks\t\t\t= { 332\t\t\t{&dtv_phandle_target, {}},}, 333}; 334U_BOOT_DEVICE(phandle_source2) = { 335\t.name\t\t= "source", 336\t.platdata\t= &dtv_phandle_source2, 337\t.platdata_size\t= sizeof(dtv_phandle_source2), 338}; 339 340''', data) 341 342 def test_phandle_single(self): 343 """Test output from a node containing a phandle reference""" 344 dtb_file = get_dtb_file('dtoc_test_phandle_single.dts') 345 output = tools.GetOutputFilename('output') 346 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 347 with open(output) as infile: 348 data = infile.read() 349 self._CheckStrings(HEADER + ''' 350struct dtd_source { 351\tstruct phandle_0_arg clocks[1]; 352}; 353struct dtd_target { 354\tfdt32_t\t\tintval; 355}; 356''', data) 357 358 def test_phandle_reorder(self): 359 """Test that phandle targets are generated before their references""" 360 dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts') 361 output = tools.GetOutputFilename('output') 362 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 363 with open(output) as infile: 364 data = infile.read() 365 self._CheckStrings(C_HEADER + ''' 366static struct dtd_target dtv_phandle_target = { 367}; 368U_BOOT_DEVICE(phandle_target) = { 369\t.name\t\t= "target", 370\t.platdata\t= &dtv_phandle_target, 371\t.platdata_size\t= sizeof(dtv_phandle_target), 372}; 373 374static struct dtd_source dtv_phandle_source2 = { 375\t.clocks\t\t\t= { 376\t\t\t{&dtv_phandle_target, {}},}, 377}; 378U_BOOT_DEVICE(phandle_source2) = { 379\t.name\t\t= "source", 380\t.platdata\t= &dtv_phandle_source2, 381\t.platdata_size\t= sizeof(dtv_phandle_source2), 382}; 383 384''', data) 385 386 def test_phandle_bad(self): 387 """Test a node containing an invalid phandle fails""" 388 dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts') 389 output = tools.GetOutputFilename('output') 390 with self.assertRaises(ValueError) as e: 391 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 392 self.assertIn("Cannot parse 'clocks' in node 'phandle-source'", 393 str(e.exception)) 394 395 def test_phandle_bad2(self): 396 """Test a phandle target missing its #*-cells property""" 397 dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts') 398 output = tools.GetOutputFilename('output') 399 with self.assertRaises(ValueError) as e: 400 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 401 self.assertIn("Node 'phandle-target' has no '#clock-cells' property", 402 str(e.exception)) 403 404 def test_aliases(self): 405 """Test output from a node with multiple compatible strings""" 406 dtb_file = get_dtb_file('dtoc_test_aliases.dts') 407 output = tools.GetOutputFilename('output') 408 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 409 with open(output) as infile: 410 data = infile.read() 411 self._CheckStrings(HEADER + ''' 412struct dtd_compat1 { 413\tfdt32_t\t\tintval; 414}; 415#define dtd_compat2_1_fred dtd_compat1 416#define dtd_compat3 dtd_compat1 417''', data) 418 419 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 420 with open(output) as infile: 421 data = infile.read() 422 self._CheckStrings(C_HEADER + ''' 423static struct dtd_compat1 dtv_spl_test = { 424\t.intval\t\t\t= 0x1, 425}; 426U_BOOT_DEVICE(spl_test) = { 427\t.name\t\t= "compat1", 428\t.platdata\t= &dtv_spl_test, 429\t.platdata_size\t= sizeof(dtv_spl_test), 430}; 431 432''', data) 433 434 def test_addresses64(self): 435 """Test output from a node with a 'reg' property with na=2, ns=2""" 436 dtb_file = get_dtb_file('dtoc_test_addr64.dts') 437 output = tools.GetOutputFilename('output') 438 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 439 with open(output) as infile: 440 data = infile.read() 441 self._CheckStrings(HEADER + ''' 442struct dtd_test1 { 443\tfdt64_t\t\treg[2]; 444}; 445struct dtd_test2 { 446\tfdt64_t\t\treg[2]; 447}; 448struct dtd_test3 { 449\tfdt64_t\t\treg[4]; 450}; 451''', data) 452 453 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 454 with open(output) as infile: 455 data = infile.read() 456 self._CheckStrings(C_HEADER + ''' 457static struct dtd_test1 dtv_test1 = { 458\t.reg\t\t\t= {0x1234, 0x5678}, 459}; 460U_BOOT_DEVICE(test1) = { 461\t.name\t\t= "test1", 462\t.platdata\t= &dtv_test1, 463\t.platdata_size\t= sizeof(dtv_test1), 464}; 465 466static struct dtd_test2 dtv_test2 = { 467\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654}, 468}; 469U_BOOT_DEVICE(test2) = { 470\t.name\t\t= "test2", 471\t.platdata\t= &dtv_test2, 472\t.platdata_size\t= sizeof(dtv_test2), 473}; 474 475static struct dtd_test3 dtv_test3 = { 476\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3}, 477}; 478U_BOOT_DEVICE(test3) = { 479\t.name\t\t= "test3", 480\t.platdata\t= &dtv_test3, 481\t.platdata_size\t= sizeof(dtv_test3), 482}; 483 484''', data) 485 486 def test_addresses32(self): 487 """Test output from a node with a 'reg' property with na=1, ns=1""" 488 dtb_file = get_dtb_file('dtoc_test_addr32.dts') 489 output = tools.GetOutputFilename('output') 490 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 491 with open(output) as infile: 492 data = infile.read() 493 self._CheckStrings(HEADER + ''' 494struct dtd_test1 { 495\tfdt32_t\t\treg[2]; 496}; 497struct dtd_test2 { 498\tfdt32_t\t\treg[4]; 499}; 500''', data) 501 502 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 503 with open(output) as infile: 504 data = infile.read() 505 self._CheckStrings(C_HEADER + ''' 506static struct dtd_test1 dtv_test1 = { 507\t.reg\t\t\t= {0x1234, 0x5678}, 508}; 509U_BOOT_DEVICE(test1) = { 510\t.name\t\t= "test1", 511\t.platdata\t= &dtv_test1, 512\t.platdata_size\t= sizeof(dtv_test1), 513}; 514 515static struct dtd_test2 dtv_test2 = { 516\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3}, 517}; 518U_BOOT_DEVICE(test2) = { 519\t.name\t\t= "test2", 520\t.platdata\t= &dtv_test2, 521\t.platdata_size\t= sizeof(dtv_test2), 522}; 523 524''', data) 525 526 def test_addresses64_32(self): 527 """Test output from a node with a 'reg' property with na=2, ns=1""" 528 dtb_file = get_dtb_file('dtoc_test_addr64_32.dts') 529 output = tools.GetOutputFilename('output') 530 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 531 with open(output) as infile: 532 data = infile.read() 533 self._CheckStrings(HEADER + ''' 534struct dtd_test1 { 535\tfdt64_t\t\treg[2]; 536}; 537struct dtd_test2 { 538\tfdt64_t\t\treg[2]; 539}; 540struct dtd_test3 { 541\tfdt64_t\t\treg[4]; 542}; 543''', data) 544 545 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 546 with open(output) as infile: 547 data = infile.read() 548 self._CheckStrings(C_HEADER + ''' 549static struct dtd_test1 dtv_test1 = { 550\t.reg\t\t\t= {0x123400000000, 0x5678}, 551}; 552U_BOOT_DEVICE(test1) = { 553\t.name\t\t= "test1", 554\t.platdata\t= &dtv_test1, 555\t.platdata_size\t= sizeof(dtv_test1), 556}; 557 558static struct dtd_test2 dtv_test2 = { 559\t.reg\t\t\t= {0x1234567890123456, 0x98765432}, 560}; 561U_BOOT_DEVICE(test2) = { 562\t.name\t\t= "test2", 563\t.platdata\t= &dtv_test2, 564\t.platdata_size\t= sizeof(dtv_test2), 565}; 566 567static struct dtd_test3 dtv_test3 = { 568\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3}, 569}; 570U_BOOT_DEVICE(test3) = { 571\t.name\t\t= "test3", 572\t.platdata\t= &dtv_test3, 573\t.platdata_size\t= sizeof(dtv_test3), 574}; 575 576''', data) 577 578 def test_addresses32_64(self): 579 """Test output from a node with a 'reg' property with na=1, ns=2""" 580 dtb_file = get_dtb_file('dtoc_test_addr32_64.dts') 581 output = tools.GetOutputFilename('output') 582 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 583 with open(output) as infile: 584 data = infile.read() 585 self._CheckStrings(HEADER + ''' 586struct dtd_test1 { 587\tfdt64_t\t\treg[2]; 588}; 589struct dtd_test2 { 590\tfdt64_t\t\treg[2]; 591}; 592struct dtd_test3 { 593\tfdt64_t\t\treg[4]; 594}; 595''', data) 596 597 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 598 with open(output) as infile: 599 data = infile.read() 600 self._CheckStrings(C_HEADER + ''' 601static struct dtd_test1 dtv_test1 = { 602\t.reg\t\t\t= {0x1234, 0x567800000000}, 603}; 604U_BOOT_DEVICE(test1) = { 605\t.name\t\t= "test1", 606\t.platdata\t= &dtv_test1, 607\t.platdata_size\t= sizeof(dtv_test1), 608}; 609 610static struct dtd_test2 dtv_test2 = { 611\t.reg\t\t\t= {0x12345678, 0x9876543210987654}, 612}; 613U_BOOT_DEVICE(test2) = { 614\t.name\t\t= "test2", 615\t.platdata\t= &dtv_test2, 616\t.platdata_size\t= sizeof(dtv_test2), 617}; 618 619static struct dtd_test3 dtv_test3 = { 620\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3}, 621}; 622U_BOOT_DEVICE(test3) = { 623\t.name\t\t= "test3", 624\t.platdata\t= &dtv_test3, 625\t.platdata_size\t= sizeof(dtv_test3), 626}; 627 628''', data) 629 630 def test_bad_reg(self): 631 """Test that a reg property with an invalid type generates an error""" 632 # Capture stderr since dtc will emit warnings for this file 633 dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True) 634 output = tools.GetOutputFilename('output') 635 with self.assertRaises(ValueError) as e: 636 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 637 self.assertIn("Node 'spl-test' reg property is not an int", 638 str(e.exception)) 639 640 def test_bad_reg2(self): 641 """Test that a reg property with an invalid cell count is detected""" 642 # Capture stderr since dtc will emit warnings for this file 643 dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True) 644 output = tools.GetOutputFilename('output') 645 with self.assertRaises(ValueError) as e: 646 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 647 self.assertIn("Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)", 648 str(e.exception)) 649 650 def test_add_prop(self): 651 """Test that a subequent node can add a new property to a struct""" 652 dtb_file = get_dtb_file('dtoc_test_add_prop.dts') 653 output = tools.GetOutputFilename('output') 654 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 655 with open(output) as infile: 656 data = infile.read() 657 self._CheckStrings(HEADER + ''' 658struct dtd_sandbox_spl_test { 659\tfdt32_t\t\tintarray; 660\tfdt32_t\t\tintval; 661}; 662''', data) 663 664 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 665 with open(output) as infile: 666 data = infile.read() 667 self._CheckStrings(C_HEADER + ''' 668static struct dtd_sandbox_spl_test dtv_spl_test = { 669\t.intval\t\t\t= 0x1, 670}; 671U_BOOT_DEVICE(spl_test) = { 672\t.name\t\t= "sandbox_spl_test", 673\t.platdata\t= &dtv_spl_test, 674\t.platdata_size\t= sizeof(dtv_spl_test), 675}; 676 677static struct dtd_sandbox_spl_test dtv_spl_test2 = { 678\t.intarray\t\t= 0x5, 679}; 680U_BOOT_DEVICE(spl_test2) = { 681\t.name\t\t= "sandbox_spl_test", 682\t.platdata\t= &dtv_spl_test2, 683\t.platdata_size\t= sizeof(dtv_spl_test2), 684}; 685 686''', data) 687 688 def testStdout(self): 689 """Test output to stdout""" 690 dtb_file = get_dtb_file('dtoc_test_simple.dts') 691 with test_util.capture_sys_output() as (stdout, stderr): 692 dtb_platdata.run_steps(['struct'], dtb_file, False, '-') 693 694 def testNoCommand(self): 695 """Test running dtoc without a command""" 696 with self.assertRaises(ValueError) as e: 697 dtb_platdata.run_steps([], '', False, '') 698 self.assertIn("Please specify a command: struct, platdata", 699 str(e.exception)) 700 701 def testBadCommand(self): 702 """Test running dtoc with an invalid command""" 703 dtb_file = get_dtb_file('dtoc_test_simple.dts') 704 output = tools.GetOutputFilename('output') 705 with self.assertRaises(ValueError) as e: 706 dtb_platdata.run_steps(['invalid-cmd'], dtb_file, False, output) 707 self.assertIn("Unknown command 'invalid-cmd': (use: struct, platdata)", 708 str(e.exception)) 709