Re: [PATCH v6 1/1] pylibfdt: Support the sequential-write interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



On Tue, Jul 10, 2018 at 02:49:07PM -0600, Simon Glass wrote:
> It is useful to be able to create a device tree from scratch using
> software. This is supported in libfdt but not currently available in the
> Python bindings.
> 
> Add a new FdtSw class to handle this, with various methods corresponding
> to the libfdt functions. When the tree is complete, calling AsFdt() will
> return the completed device-tree object.
> 
> Signed-off-by: Simon Glass <sjg@xxxxxxxxxxxx>

Applied, thanks.

> ---
> 
> Changes in v6:
> - Adjust tests to suit
> - Correct call to range() in test which overwrites an existing node
> - Create an FdtRo base class and make Fdt and FdtSw be subclasses
> 
> Changes in v5:
> - Drop error return from resize()
> - Drop the unnecessary check for a negative size in the FdtSw() constructor
> - Drop work-around for apparent bug in fdt_resize()
> - Fix copying logic in as_fdt(), and add a test for it
> 
> Changes in v4:
> - Drop patches previously indicated as applied (but not yet present in master)
> - Make resizing reactive (to -FDT_ERR_NOTFOUND) instead of proactive
> 
> Changes in v3:
> - Add a separate comment explaining the purpose of the FdtSw context manager
> - Adjust operation of as_fdt() to include calling fdt_finish()
> - Drop unnecessary data copy in resize() an rely on fdt_resize() instead
> - Rename AddNode() to add_node()
> - Rename AsFdt() to as_fdt()
> - Rename _fdt_property() to fdt_property_stub()
> - Rename the size passed to the FdtSw() to a hint only
> - Use fdtsw instead of fdtrw as internal variable in FdtSw
> 
>  pylibfdt/libfdt.i       | 460 +++++++++++++++++++++++++++++++++-------
>  tests/pylibfdt_tests.py | 121 ++++++++++-
>  2 files changed, 498 insertions(+), 83 deletions(-)
> 
> diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i
> index aed5390..fc53a8c 100644
> --- a/pylibfdt/libfdt.i
> +++ b/pylibfdt/libfdt.i
> @@ -57,6 +57,18 @@
>  %{
>  #define SWIG_FILE_WITH_INIT
>  #include "libfdt.h"
> +
> +/*
> + * We rename this function here to avoid problems with swig, since we also have
> + * a struct called fdt_property. That struct causes swig to create a class in
> + * libfdt.py called fdt_property(), which confuses things.
> + */
> +static int fdt_property_stub(void *fdt, const char *name, const char *val,
> +                             int len)
> +{
> +    return fdt_property(fdt, name, val, len);
> +}
> +
>  %}
>  
>  %pythoncode %{
> @@ -88,6 +100,7 @@ import struct
>  # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
>  # instead of raising an exception.
>  QUIET_NOTFOUND = (NOTFOUND,)
> +QUIET_NOSPACE = (NOSPACE,)
>  
>  
>  class FdtException(Exception):
> @@ -153,22 +166,18 @@ def check_err_null(val, quiet=()):
>              raise FdtException(val)
>      return val
>  
> -class Fdt:
> -    """Device tree class, supporting all operations
> -
> -    The Fdt object is created is created from a device tree binary file,
> -    e.g. with something like:
> +class FdtRo(object):
> +    """Class for a read-only device-tree
>  
> -       fdt = Fdt(open("filename.dtb").read())
> +    This is a base class used by FdtRw (read-write access) and FdtSw
> +    (sequential-write access). It implements read-only access to the
> +    device tree.
>  
> -    Operations can then be performed using the methods in this class. Each
> -    method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
> +    Here are the three classes and when you should use them:
>  
> -    All methods raise an FdtException if an error occurs. To avoid this
> -    behaviour a 'quiet' parameter is provided for some functions. This
> -    defaults to empty, but you can pass a list of errors that you expect.
> -    If one of these errors occurs, the function will return an error number
> -    (e.g. -NOTFOUND).
> +        FdtRo - read-only access to an existing FDT
> +        FdtRw - read-write access to an existing FDT (most common case)
> +        FdtSw - for creating a new FDT, as well as allowing read-only access
>      """
>      def __init__(self, data):
>          self._fdt = bytearray(data)
> @@ -433,6 +442,91 @@ class Fdt:
>              return pdata
>          return Property(pdata[0], pdata[1])
>  
> +    def getprop(self, nodeoffset, prop_name, quiet=()):
> +        """Get a property from a node
> +
> +        Args:
> +            nodeoffset: Node offset containing property to get
> +            prop_name: Name of property to get
> +            quiet: Errors to ignore (empty to raise on all errors)
> +
> +        Returns:
> +            Value of property as a Property object (which can be used as a
> +               bytearray/string), or -ve error number. On failure, returns an
> +               integer error
> +
> +        Raises:
> +            FdtError if any error occurs (e.g. the property is not found)
> +        """
> +        pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
> +                               quiet)
> +        if isinstance(pdata, (int)):
> +            return pdata
> +        return Property(prop_name, bytearray(pdata[0]))
> +
> +    def get_phandle(self, nodeoffset):
> +        """Get the phandle of a node
> +
> +        Args:
> +            nodeoffset: Node offset to check
> +
> +        Returns:
> +            phandle of node, or 0 if the node has no phandle or another error
> +            occurs
> +        """
> +        return fdt_get_phandle(self._fdt, nodeoffset)
> +
> +    def parent_offset(self, nodeoffset, quiet=()):
> +        """Get the offset of a node's parent
> +
> +        Args:
> +            nodeoffset: Node offset to check
> +            quiet: Errors to ignore (empty to raise on all errors)
> +
> +        Returns:
> +            The offset of the parent node, if any
> +
> +        Raises:
> +            FdtException if no parent found or other error occurs
> +        """
> +        return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
> +
> +    def node_offset_by_phandle(self, phandle, quiet=()):
> +        """Get the offset of a node with the given phandle
> +
> +        Args:
> +            phandle: Phandle to search for
> +            quiet: Errors to ignore (empty to raise on all errors)
> +
> +        Returns:
> +            The offset of node with that phandle, if any
> +
> +        Raises:
> +            FdtException if no node found or other error occurs
> +        """
> +        return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
> +
> +
> +class Fdt(FdtRo):
> +    """Device tree class, supporting all operations
> +
> +    The Fdt object is created is created from a device tree binary file,
> +    e.g. with something like:
> +
> +       fdt = Fdt(open("filename.dtb").read())
> +
> +    Operations can then be performed using the methods in this class. Each
> +    method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
> +
> +    All methods raise an FdtException if an error occurs. To avoid this
> +    behaviour a 'quiet' parameter is provided for some functions. This
> +    defaults to empty, but you can pass a list of errors that you expect.
> +    If one of these errors occurs, the function will return an error number
> +    (e.g. -NOTFOUND).
> +    """
> +    def __init__(self, data):
> +        FdtRo.__init__(self, data)
> +
>      @staticmethod
>      def create_empty_tree(size, quiet=()):
>          """Create an empty device tree ready for use
> @@ -486,55 +580,6 @@ class Fdt:
>          del self._fdt[self.totalsize():]
>          return err
>  
> -    def getprop(self, nodeoffset, prop_name, quiet=()):
> -        """Get a property from a node
> -
> -        Args:
> -            nodeoffset: Node offset containing property to get
> -            prop_name: Name of property to get
> -            quiet: Errors to ignore (empty to raise on all errors)
> -
> -        Returns:
> -            Value of property as a Property object (which can be used as a
> -               bytearray/string), or -ve error number. On failure, returns an
> -               integer error
> -
> -        Raises:
> -            FdtError if any error occurs (e.g. the property is not found)
> -        """
> -        pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
> -                               quiet)
> -        if isinstance(pdata, (int)):
> -            return pdata
> -        return Property(prop_name, bytearray(pdata[0]))
> -
> -    def get_phandle(self, nodeoffset):
> -        """Get the phandle of a node
> -
> -        Args:
> -            nodeoffset: Node offset to check
> -
> -        Returns:
> -            phandle of node, or 0 if the node has no phandle or another error
> -            occurs
> -        """
> -        return fdt_get_phandle(self._fdt, nodeoffset)
> -
> -    def parent_offset(self, nodeoffset, quiet=()):
> -        """Get the offset of a node's parent
> -
> -        Args:
> -            nodeoffset: Node offset to check
> -            quiet: Errors to ignore (empty to raise on all errors)
> -
> -        Returns:
> -            The offset of the parent node, if any
> -
> -        Raises:
> -            FdtException if no parent found or other error occurs
> -        """
> -        return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
> -
>      def set_name(self, nodeoffset, name, quiet=()):
>          """Set the name of a node
>  
> @@ -640,21 +685,6 @@ class Fdt:
>          """
>          return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
>  
> -    def node_offset_by_phandle(self, phandle, quiet=()):
> -        """Get the offset of a node with the given phandle
> -
> -        Args:
> -            phandle: Phandle to search for
> -            quiet: Errors to ignore (empty to raise on all errors)
> -
> -        Returns:
> -            The offset of node with that phandle, if any
> -
> -        Raises:
> -            FdtException if no node found or other error occurs
> -        """
> -        return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
> -
>  
>  class Property(bytearray):
>      """Holds a device tree property name and value.
> @@ -693,6 +723,268 @@ class Property(bytearray):
>          if 0 in self[:-1]:
>              raise ValueError('Property contains embedded nul characters')
>          return self[:-1].decode('utf-8')
> +
> +
> +class FdtSw(FdtRo):
> +    """Software interface to create a device tree from scratch
> +
> +    The methods in this class work by adding to an existing 'partial' device
> +    tree buffer of a fixed size created by instantiating this class. When the
> +    tree is complete, call as_fdt() to obtain a device tree ready to be used.
> +
> +    Similarly with nodes, a new node is started with begin_node() and finished
> +    with end_node().
> +
> +    The context manager functions can be used to make this a bit easier:
> +
> +    # First create the device tree with a node and property:
> +    sw = FdtSw()
> +    with sw.add_node('node'):
> +        sw.property_u32('reg', 2)
> +    fdt = sw.as_fdt()
> +
> +    # Now we can use it as a real device tree
> +    fdt.setprop_u32(0, 'reg', 3)
> +
> +    The size hint provides a starting size for the space to be used by the
> +    device tree. This will be increased automatically as needed as new items
> +    are added to the tree.
> +    """
> +    INC_SIZE = 1024  # Expand size by this much when out of space
> +
> +    def __init__(self, size_hint=None):
> +        """Create a new FdtSw object
> +
> +        Args:
> +            size_hint: A hint as to the initial size to use
> +
> +        Raises:
> +            ValueError if size_hint is negative
> +
> +        Returns:
> +            FdtSw object on success, else integer error code (if not raising)
> +        """
> +        if not size_hint:
> +            size_hint = self.INC_SIZE
> +        fdtsw = bytearray(size_hint)
> +        err = check_err(fdt_create(fdtsw, size_hint))
> +        if err:
> +            return err
> +        self._fdt = fdtsw
> +
> +    def as_fdt(self):
> +        """Convert a FdtSw into an Fdt so it can be accessed as normal
> +
> +        Creates a new Fdt object from the work-in-progress device tree. This
> +        does not call fdt_finish() on the current object, so it is possible to
> +        add more nodes/properties and call as_fdt() again to get an updated
> +        tree.
> +
> +        Returns:
> +            Fdt object allowing access to the newly created device tree
> +        """
> +        fdtsw = bytearray(self._fdt)
> +        check_err(fdt_finish(fdtsw))
> +        return Fdt(fdtsw)
> +
> +    def check_space(self, val):
> +        """Check if we need to add more space to the FDT
> +
> +        This should be called with the error code from an operation. If this is
> +        -NOSPACE then the FDT will be expanded to have more space, and True will
> +        be returned, indicating that the operation needs to be tried again.
> +
> +        Args:
> +            val: Return value from the operation that was attempted
> +
> +        Returns:
> +            True if the operation must be retried, else False
> +        """
> +        if check_err(val, QUIET_NOSPACE) < 0:
> +            self.resize(len(self._fdt) + self.INC_SIZE)
> +            return True
> +        return False
> +
> +    def resize(self, size):
> +        """Resize the buffer to accommodate a larger tree
> +
> +        Args:
> +            size: New size of tree
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        fdt = bytearray(size)
> +        err = check_err(fdt_resize(self._fdt, fdt, size))
> +        self._fdt = fdt
> +
> +    def add_reservemap_entry(self, addr, size):
> +        """Add a new memory reserve map entry
> +
> +        Once finished adding, you must call finish_reservemap().
> +
> +        Args:
> +            addr: 64-bit start address
> +            size: 64-bit size
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
> +                                                        size)):
> +            pass
> +
> +    def finish_reservemap(self):
> +        """Indicate that there are no more reserve map entries to add
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_finish_reservemap(self._fdt)):
> +            pass
> +
> +    def begin_node(self, name):
> +        """Begin a new node
> +
> +        Use this before adding properties to the node. Then call end_node() to
> +        finish it. You can also use the context manager as shown in the FdtSw
> +        class comment.
> +
> +        Args:
> +            name: Name of node to begin
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_begin_node(self._fdt, name)):
> +            pass
> +
> +    def property_string(self, name, string):
> +        """Add a property with a string value
> +
> +        The string will be nul-terminated when written to the device tree
> +
> +        Args:
> +            name: Name of property to add
> +            string: String value of property
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_property_string(self._fdt, name, string)):
> +            pass
> +
> +    def property_u32(self, name, val):
> +        """Add a property with a 32-bit value
> +
> +        Write a single-cell value to the device tree
> +
> +        Args:
> +            name: Name of property to add
> +            val: Value of property
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_property_u32(self._fdt, name, val)):
> +            pass
> +
> +    def property_u64(self, name, val):
> +        """Add a property with a 64-bit value
> +
> +        Write a double-cell value to the device tree in big-endian format
> +
> +        Args:
> +            name: Name of property to add
> +            val: Value of property
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_property_u64(self._fdt, name, val)):
> +            pass
> +
> +    def property_cell(self, name, val):
> +        """Add a property with a single-cell value
> +
> +        Write a single-cell value to the device tree
> +
> +        Args:
> +            name: Name of property to add
> +            val: Value of property
> +            quiet: Errors to ignore (empty to raise on all errors)
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_property_cell(self._fdt, name, val)):
> +            pass
> +
> +    def property(self, name, val):
> +        """Add a property
> +
> +        Write a new property with the given value to the device tree. The value
> +        is taken as is and is not nul-terminated
> +
> +        Args:
> +            name: Name of property to add
> +            val: Value of property
> +            quiet: Errors to ignore (empty to raise on all errors)
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_property_stub(self._fdt, name, val,
> +                                                 len(val))):
> +            pass
> +
> +    def end_node(self):
> +        """End a node
> +
> +        Use this after adding properties to a node to close it off. You can also
> +        use the context manager as shown in the FdtSw class comment.
> +
> +        Args:
> +            quiet: Errors to ignore (empty to raise on all errors)
> +
> +        Raises:
> +            FdtException on any error
> +        """
> +        while self.check_space(fdt_end_node(self._fdt)):
> +            pass
> +
> +    def add_node(self, name):
> +        """Create a new context for adding a node
> +
> +        When used in a 'with' clause this starts a new node and finishes it
> +        afterward.
> +
> +        Args:
> +            name: Name of node to add
> +        """
> +        return NodeAdder(self, name)
> +
> +
> +class NodeAdder():
> +    """Class to provide a node context
> +
> +    This allows you to add nodes in a more natural way:
> +
> +        with fdtsw.add_node('name'):
> +            fdtsw.property_string('test', 'value')
> +
> +    The node is automatically completed with a call to end_node() when the
> +    context exits.
> +    """
> +    def __init__(self, fdtsw, name):
> +        self._fdt = fdtsw
> +        self._name = name
> +
> +    def __enter__(self):
> +        self._fdt.begin_node(self._name)
> +
> +    def __exit__(self, type, value, traceback):
> +        self._fdt.end_node()
>  %}
>  
>  %rename(fdt_property) fdt_property_func;
> @@ -757,6 +1049,11 @@ typedef uint32_t fdt32_t;
>      $1 = PyString_AsString($input);   /* char *str */
>  }
>  
> +/* typemap used for fdt_add_reservemap_entry() */
> +%typemap(in) uint64_t {
> +   $1 = PyLong_AsUnsignedLong($input);
> +}
> +
>  /* typemaps used for fdt_next_node() */
>  %typemap(in, numinputs=1) int *depth (int depth) {
>     depth = (int) PyInt_AsLong($input);
> @@ -800,4 +1097,13 @@ uint32_t fdt_boot_cpuid_phys(const void *fdt);
>  uint32_t fdt_size_dt_strings(const void *fdt);
>  uint32_t fdt_size_dt_struct(const void *fdt);
>  
> +int fdt_property_string(void *fdt, const char *name, const char *val);
> +int fdt_property_cell(void *fdt, const char *name, uint32_t val);
> +
> +/*
> + * This function has a stub since the name fdt_property is used for both a
> +  * function and a struct, which confuses SWIG.
> + */
> +int fdt_property_stub(void *fdt, const char *name, const char *val, int len);
> +
>  %include <../libfdt/libfdt.h>
> diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
> index 9f3e55a..e61fda9 100644
> --- a/tests/pylibfdt_tests.py
> +++ b/tests/pylibfdt_tests.py
> @@ -56,17 +56,32 @@ import unittest
>  
>  sys.path.insert(0, '../pylibfdt')
>  import libfdt
> -from libfdt import Fdt, FdtException, QUIET_NOTFOUND, QUIET_ALL
> -
> -small_size = 160
> -full_size = 1024
> +from libfdt import Fdt, FdtSw, FdtException, QUIET_NOTFOUND, QUIET_ALL
> +
> +TEST_ADDR_1H = 0xdeadbeef
> +TEST_ADDR_1L = 0x00000000
> +TEST_ADDR_1 = (TEST_ADDR_1H << 32) | TEST_ADDR_1L
> +TEST_ADDR_1 = 0x8000000000000000
> +TEST_SIZE_1H = 0x00000000
> +TEST_SIZE_1L = 0x00100000
> +TEST_SIZE_1 = (TEST_SIZE_1H << 32) | TEST_SIZE_1L
> +TEST_ADDR_2H = 0
> +TEST_ADDR_2L = 123456789
> +TEST_ADDR_2 = (TEST_ADDR_2H << 32) | TEST_ADDR_2L
> +TEST_SIZE_2H = 0
> +TEST_SIZE_2L = 010000
> +TEST_SIZE_2 = (TEST_SIZE_2H << 32) | TEST_SIZE_2L
>  
>  TEST_VALUE_1 = 0xdeadbeef
> +TEST_VALUE_2 = 123456789
>  
>  TEST_VALUE64_1H = 0xdeadbeef
>  TEST_VALUE64_1L = 0x01abcdef
>  TEST_VALUE64_1 = (TEST_VALUE64_1H << 32) | TEST_VALUE64_1L
>  
> +PHANDLE_1 = 0x2000
> +PHANDLE_2 = 0x2001
> +
>  TEST_STRING_1 = 'hello world'
>  TEST_STRING_2 = 'hi world'
>  TEST_STRING_3 = u'unicode ' + unichr(467)
> @@ -94,8 +109,8 @@ def _ReadFdt(fname):
>      """
>      return libfdt.Fdt(open(fname).read())
>  
> -class PyLibfdtTests(unittest.TestCase):
> -    """Test class for pylibfdt
> +class PyLibfdtBasicTests(unittest.TestCase):
> +    """Test class for basic pylibfdt access functions
>  
>      Properties:
>          fdt: Device tree file used for testing
> @@ -481,5 +496,99 @@ class PyLibfdtTests(unittest.TestCase):
>          self.assertIn('embedded nul', str(e.exception))
>  
>  
> +class PyLibfdtSwTests(unittest.TestCase):
> +    """Test class for pylibfdt sequential-write DT creation
> +    """
> +    def assertOk(self, err_code):
> +        self.assertEquals(0, err_code)
> +
> +    def testCreate(self):
> +        # First check the minimum size and also the FdtSw() constructor
> +        with self.assertRaisesRegexp(FdtException, get_err(libfdt.NOSPACE)):
> +            self.assertEquals(-libfdt.NOSPACE, FdtSw(3))
> +
> +        sw = FdtSw()
> +        sw.add_reservemap_entry(TEST_ADDR_1, TEST_SIZE_1)
> +        sw.add_reservemap_entry(TEST_ADDR_2, TEST_SIZE_2)
> +        sw.finish_reservemap()
> +
> +        sw.begin_node('')
> +        sw.property_string('compatible', 'test_tree1')
> +        sw.property_u32('prop-int', TEST_VALUE_1)
> +
> +        sw.property_u32('prop-int', TEST_VALUE_1)
> +        sw.property_u64('prop-int64', TEST_VALUE64_1)
> +        sw.property_string('prop-str', TEST_STRING_1)
> +        sw.property_u32('#address-cells', 1)
> +        sw.property_u32('#size-cells', 0)
> +
> +        sw.begin_node('subnode@1')
> +        sw.property_string('compatible', 'subnode1')
> +        sw.property_u32('reg', 1)
> +        sw.property_cell('prop-int', TEST_VALUE_1)
> +        sw.begin_node('subsubnode')
> +        sw.property('compatible', 'subsubnode1\0subsubnode')
> +        sw.property_cell('prop-int', TEST_VALUE_1)
> +        sw.end_node()
> +        sw.begin_node('ss1')
> +        sw.end_node()
> +        sw.end_node()
> +
> +        for i in range(2, 11):
> +            with sw.add_node('subnode@%d' % i):
> +                sw.property_u32('reg', 2)
> +                sw.property_cell('linux,phandle', PHANDLE_1)
> +                sw.property_cell('prop-int', TEST_VALUE_2)
> +                sw.property_u32('#address-cells', 1)
> +                sw.property_u32('#size-cells', 0)
> +                with sw.add_node('subsubnode@0'):
> +                    sw.property_u32('reg', 0)
> +                    sw.property_cell('phandle', PHANDLE_2)
> +                    sw.property('compatible', 'subsubnode2\0subsubnode')
> +                    sw.property_cell('prop-int', TEST_VALUE_2)
> +                with sw.add_node('ss2'):
> +                    pass
> +        sw.end_node()
> +
> +        fdt = sw.as_fdt()
> +        self.assertEqual(2, fdt.num_mem_rsv())
> +        self.assertEqual([TEST_ADDR_1, TEST_SIZE_1], fdt.get_mem_rsv(0))
> +
> +        # Make sure we can add a few more things
> +        with sw.add_node('another'):
> +            sw.property_u32('reg', 3)
> +
> +        # Make sure we can read from the tree too
> +        node = sw.path_offset('/subnode@1')
> +        self.assertEqual('subnode1' + chr(0), sw.getprop(node, 'compatible'))
> +
> +        # Make sure we did at least two resizes
> +        self.assertTrue(len(fdt.as_bytearray()) > FdtSw.INC_SIZE * 2)
> +
> +
> +class PyLibfdtRoTests(unittest.TestCase):
> +    """Test class for read-only pylibfdt access functions
> +
> +    This just tests a few simple cases. Most of the tests are in
> +    PyLibfdtBasicTests.
> +
> +    Properties:
> +        fdt: Device tree file used for testing
> +    """
> +
> +    def setUp(self):
> +        """Read in the device tree we use for testing"""
> +        self.fdt = libfdt.FdtRo(open('test_tree1.dtb').read())
> +
> +    def testAccess(self):
> +        """Basic sanity check for the FdtRo class"""
> +        node = self.fdt.path_offset('/subnode@1')
> +        self.assertEqual('subnode1' + chr(0),
> +                         self.fdt.getprop(node, 'compatible'))
> +        node = self.fdt.first_subnode(node)
> +        self.assertEqual('this is a placeholder string\0string2\0',
> +                         self.fdt.getprop(node, 'placeholder'))
> +
> +
>  if __name__ == "__main__":
>      unittest.main()

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux