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