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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 capture_stderr=True) 390 output = tools.GetOutputFilename('output') 391 with self.assertRaises(ValueError) as e: 392 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 393 self.assertIn("Cannot parse 'clocks' in node 'phandle-source'", 394 str(e.exception)) 395 396 def test_phandle_bad2(self): 397 """Test a phandle target missing its #*-cells property""" 398 dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts', 399 capture_stderr=True) 400 output = tools.GetOutputFilename('output') 401 with self.assertRaises(ValueError) as e: 402 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 403 self.assertIn("Node 'phandle-target' has no '#clock-cells' property", 404 str(e.exception)) 405 406 def test_aliases(self): 407 """Test output from a node with multiple compatible strings""" 408 dtb_file = get_dtb_file('dtoc_test_aliases.dts') 409 output = tools.GetOutputFilename('output') 410 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 411 with open(output) as infile: 412 data = infile.read() 413 self._CheckStrings(HEADER + ''' 414struct dtd_compat1 { 415\tfdt32_t\t\tintval; 416}; 417#define dtd_compat2_1_fred dtd_compat1 418#define dtd_compat3 dtd_compat1 419''', data) 420 421 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 422 with open(output) as infile: 423 data = infile.read() 424 self._CheckStrings(C_HEADER + ''' 425static const struct dtd_compat1 dtv_spl_test = { 426\t.intval\t\t\t= 0x1, 427}; 428U_BOOT_DEVICE(spl_test) = { 429\t.name\t\t= "compat1", 430\t.platdata\t= &dtv_spl_test, 431\t.platdata_size\t= sizeof(dtv_spl_test), 432}; 433 434''', data) 435 436 def test_addresses64(self): 437 """Test output from a node with a 'reg' property with na=2, ns=2""" 438 dtb_file = get_dtb_file('dtoc_test_addr64.dts') 439 output = tools.GetOutputFilename('output') 440 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 441 with open(output) as infile: 442 data = infile.read() 443 self._CheckStrings(HEADER + ''' 444struct dtd_test1 { 445\tfdt64_t\t\treg[2]; 446}; 447struct dtd_test2 { 448\tfdt64_t\t\treg[2]; 449}; 450struct dtd_test3 { 451\tfdt64_t\t\treg[4]; 452}; 453''', data) 454 455 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 456 with open(output) as infile: 457 data = infile.read() 458 self._CheckStrings(C_HEADER + ''' 459static const struct dtd_test1 dtv_test1 = { 460\t.reg\t\t\t= {0x1234, 0x5678}, 461}; 462U_BOOT_DEVICE(test1) = { 463\t.name\t\t= "test1", 464\t.platdata\t= &dtv_test1, 465\t.platdata_size\t= sizeof(dtv_test1), 466}; 467 468static const struct dtd_test2 dtv_test2 = { 469\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654}, 470}; 471U_BOOT_DEVICE(test2) = { 472\t.name\t\t= "test2", 473\t.platdata\t= &dtv_test2, 474\t.platdata_size\t= sizeof(dtv_test2), 475}; 476 477static const struct dtd_test3 dtv_test3 = { 478\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3}, 479}; 480U_BOOT_DEVICE(test3) = { 481\t.name\t\t= "test3", 482\t.platdata\t= &dtv_test3, 483\t.platdata_size\t= sizeof(dtv_test3), 484}; 485 486''', data) 487 488 def test_addresses32(self): 489 """Test output from a node with a 'reg' property with na=1, ns=1""" 490 dtb_file = get_dtb_file('dtoc_test_addr32.dts') 491 output = tools.GetOutputFilename('output') 492 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 493 with open(output) as infile: 494 data = infile.read() 495 self._CheckStrings(HEADER + ''' 496struct dtd_test1 { 497\tfdt32_t\t\treg[2]; 498}; 499struct dtd_test2 { 500\tfdt32_t\t\treg[4]; 501}; 502''', data) 503 504 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 505 with open(output) as infile: 506 data = infile.read() 507 self._CheckStrings(C_HEADER + ''' 508static const struct dtd_test1 dtv_test1 = { 509\t.reg\t\t\t= {0x1234, 0x5678}, 510}; 511U_BOOT_DEVICE(test1) = { 512\t.name\t\t= "test1", 513\t.platdata\t= &dtv_test1, 514\t.platdata_size\t= sizeof(dtv_test1), 515}; 516 517static const struct dtd_test2 dtv_test2 = { 518\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3}, 519}; 520U_BOOT_DEVICE(test2) = { 521\t.name\t\t= "test2", 522\t.platdata\t= &dtv_test2, 523\t.platdata_size\t= sizeof(dtv_test2), 524}; 525 526''', data) 527 528 def test_addresses64_32(self): 529 """Test output from a node with a 'reg' property with na=2, ns=1""" 530 dtb_file = get_dtb_file('dtoc_test_addr64_32.dts') 531 output = tools.GetOutputFilename('output') 532 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 533 with open(output) as infile: 534 data = infile.read() 535 self._CheckStrings(HEADER + ''' 536struct dtd_test1 { 537\tfdt64_t\t\treg[2]; 538}; 539struct dtd_test2 { 540\tfdt64_t\t\treg[2]; 541}; 542struct dtd_test3 { 543\tfdt64_t\t\treg[4]; 544}; 545''', data) 546 547 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 548 with open(output) as infile: 549 data = infile.read() 550 self._CheckStrings(C_HEADER + ''' 551static const struct dtd_test1 dtv_test1 = { 552\t.reg\t\t\t= {0x123400000000, 0x5678}, 553}; 554U_BOOT_DEVICE(test1) = { 555\t.name\t\t= "test1", 556\t.platdata\t= &dtv_test1, 557\t.platdata_size\t= sizeof(dtv_test1), 558}; 559 560static const struct dtd_test2 dtv_test2 = { 561\t.reg\t\t\t= {0x1234567890123456, 0x98765432}, 562}; 563U_BOOT_DEVICE(test2) = { 564\t.name\t\t= "test2", 565\t.platdata\t= &dtv_test2, 566\t.platdata_size\t= sizeof(dtv_test2), 567}; 568 569static const struct dtd_test3 dtv_test3 = { 570\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3}, 571}; 572U_BOOT_DEVICE(test3) = { 573\t.name\t\t= "test3", 574\t.platdata\t= &dtv_test3, 575\t.platdata_size\t= sizeof(dtv_test3), 576}; 577 578''', data) 579 580 def test_addresses32_64(self): 581 """Test output from a node with a 'reg' property with na=1, ns=2""" 582 dtb_file = get_dtb_file('dtoc_test_addr32_64.dts') 583 output = tools.GetOutputFilename('output') 584 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 585 with open(output) as infile: 586 data = infile.read() 587 self._CheckStrings(HEADER + ''' 588struct dtd_test1 { 589\tfdt64_t\t\treg[2]; 590}; 591struct dtd_test2 { 592\tfdt64_t\t\treg[2]; 593}; 594struct dtd_test3 { 595\tfdt64_t\t\treg[4]; 596}; 597''', data) 598 599 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 600 with open(output) as infile: 601 data = infile.read() 602 self._CheckStrings(C_HEADER + ''' 603static const struct dtd_test1 dtv_test1 = { 604\t.reg\t\t\t= {0x1234, 0x567800000000}, 605}; 606U_BOOT_DEVICE(test1) = { 607\t.name\t\t= "test1", 608\t.platdata\t= &dtv_test1, 609\t.platdata_size\t= sizeof(dtv_test1), 610}; 611 612static const struct dtd_test2 dtv_test2 = { 613\t.reg\t\t\t= {0x12345678, 0x9876543210987654}, 614}; 615U_BOOT_DEVICE(test2) = { 616\t.name\t\t= "test2", 617\t.platdata\t= &dtv_test2, 618\t.platdata_size\t= sizeof(dtv_test2), 619}; 620 621static const struct dtd_test3 dtv_test3 = { 622\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3}, 623}; 624U_BOOT_DEVICE(test3) = { 625\t.name\t\t= "test3", 626\t.platdata\t= &dtv_test3, 627\t.platdata_size\t= sizeof(dtv_test3), 628}; 629 630''', data) 631 632 def test_bad_reg(self): 633 """Test that a reg property with an invalid type generates an error""" 634 # Capture stderr since dtc will emit warnings for this file 635 dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True) 636 output = tools.GetOutputFilename('output') 637 with self.assertRaises(ValueError) as e: 638 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 639 self.assertIn("Node 'spl-test' reg property is not an int", 640 str(e.exception)) 641 642 def test_bad_reg2(self): 643 """Test that a reg property with an invalid cell count is detected""" 644 # Capture stderr since dtc will emit warnings for this file 645 dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True) 646 output = tools.GetOutputFilename('output') 647 with self.assertRaises(ValueError) as e: 648 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 649 self.assertIn("Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)", 650 str(e.exception)) 651 652 def test_add_prop(self): 653 """Test that a subequent node can add a new property to a struct""" 654 dtb_file = get_dtb_file('dtoc_test_add_prop.dts') 655 output = tools.GetOutputFilename('output') 656 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 657 with open(output) as infile: 658 data = infile.read() 659 self._CheckStrings(HEADER + ''' 660struct dtd_sandbox_spl_test { 661\tfdt32_t\t\tintarray; 662\tfdt32_t\t\tintval; 663}; 664''', data) 665 666 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 667 with open(output) as infile: 668 data = infile.read() 669 self._CheckStrings(C_HEADER + ''' 670static const struct dtd_sandbox_spl_test dtv_spl_test = { 671\t.intval\t\t\t= 0x1, 672}; 673U_BOOT_DEVICE(spl_test) = { 674\t.name\t\t= "sandbox_spl_test", 675\t.platdata\t= &dtv_spl_test, 676\t.platdata_size\t= sizeof(dtv_spl_test), 677}; 678 679static const struct dtd_sandbox_spl_test dtv_spl_test2 = { 680\t.intarray\t\t= 0x5, 681}; 682U_BOOT_DEVICE(spl_test2) = { 683\t.name\t\t= "sandbox_spl_test", 684\t.platdata\t= &dtv_spl_test2, 685\t.platdata_size\t= sizeof(dtv_spl_test2), 686}; 687 688''', data) 689 690 def testStdout(self): 691 """Test output to stdout""" 692 dtb_file = get_dtb_file('dtoc_test_simple.dts') 693 with test_util.capture_sys_output() as (stdout, stderr): 694 dtb_platdata.run_steps(['struct'], dtb_file, False, '-') 695 696 def testNoCommand(self): 697 """Test running dtoc without a command""" 698 with self.assertRaises(ValueError) as e: 699 dtb_platdata.run_steps([], '', False, '') 700 self.assertIn("Please specify a command: struct, platdata", 701 str(e.exception)) 702 703 def testBadCommand(self): 704 """Test running dtoc with an invalid command""" 705 dtb_file = get_dtb_file('dtoc_test_simple.dts') 706 output = tools.GetOutputFilename('output') 707 with self.assertRaises(ValueError) as e: 708 dtb_platdata.run_steps(['invalid-cmd'], dtb_file, False, output) 709 self.assertIn("Unknown command 'invalid-cmd': (use: struct, platdata)", 710 str(e.exception)) 711