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