This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 1636f65725542693ed1d2941b58c6d6485ff055b
Author: Christopher Collins <ccoll...@apache.org>
AuthorDate: Wed Jan 17 17:13:14 2018 -0800

    cborattr library
    
    This is used for parsing incoming mcumgr requests.  Destructures mcumgr
    packets and populates corresponding field variables.
    
    This comes from Apache Mynewt.
---
 cborattr/CMakeLists.txt                            |   7 +
 cborattr/include/cborattr/cborattr.h               | 153 ++++++++
 cborattr/pkg.yml                                   |  29 ++
 cborattr/src/cborattr.c                            | 423 +++++++++++++++++++++
 cborattr/syscfg.yml                                |  24 ++
 cborattr/test/pkg.yml                              |  30 ++
 cborattr/test/src/test_cborattr.c                  |  49 +++
 cborattr/test/src/test_cborattr.h                  |  57 +++
 cborattr/test/src/test_cborattr_utils.c            |  35 ++
 cborattr/test/src/testcases/cborattr_decode1.c     |  83 ++++
 .../src/testcases/cborattr_decode_bool_array.c     | 101 +++++
 .../test/src/testcases/cborattr_decode_int_array.c | 143 +++++++
 .../test/src/testcases/cborattr_decode_obj_array.c | 109 ++++++
 .../test/src/testcases/cborattr_decode_object.c    | 198 ++++++++++
 .../src/testcases/cborattr_decode_object_array.c   | 126 ++++++
 .../test/src/testcases/cborattr_decode_partial.c   |  47 +++
 .../test/src/testcases/cborattr_decode_simple.c    | 123 ++++++
 .../src/testcases/cborattr_decode_string_array.c   | 135 +++++++
 .../src/testcases/cborattr_decode_substring_key.c  | 111 ++++++
 .../src/testcases/cborattr_decode_unnamed_array.c  |  99 +++++
 20 files changed, 2082 insertions(+)

diff --git a/cborattr/CMakeLists.txt b/cborattr/CMakeLists.txt
new file mode 100644
index 0000000..2f22bd0
--- /dev/null
+++ b/cborattr/CMakeLists.txt
@@ -0,0 +1,7 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cborattr/src/cborattr.c
+)
diff --git a/cborattr/include/cborattr/cborattr.h 
b/cborattr/include/cborattr/cborattr.h
new file mode 100644
index 0000000..1cc14b3
--- /dev/null
+++ b/cborattr/include/cborattr/cborattr.h
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#ifndef CBORATTR_H
+#define CBORATTR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include "cbor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This library wraps the tinycbor decoder with a attribute based decoder
+ * suitable for decoding a binary version of json.  Specifically, the
+ * contents of the cbor contains pairs of attributes.  where the attribute
+ * is a key/value pair.  keys are always text strings, but values can be
+ * many different things (enumerated below) */
+
+typedef enum CborAttrType {
+    CborAttrIntegerType = 1,
+    CborAttrUnsignedIntegerType,
+    CborAttrByteStringType,
+    CborAttrTextStringType,
+    CborAttrBooleanType,
+    CborAttrFloatType,
+    CborAttrDoubleType,
+    CborAttrArrayType,
+    CborAttrObjectType,
+    CborAttrStructObjectType,
+    CborAttrNullType,
+} CborAttrType;
+
+struct cbor_attr_t;
+
+struct cbor_enum_t {
+    char *name;
+    long long int value;
+};
+
+struct cbor_array_t {
+    CborAttrType element_type;
+    union {
+        struct {
+            const struct cbor_attr_t *subtype;
+            char *base;
+            size_t stride;
+        } objects;
+        struct {
+            char **ptrs;
+            char *store;
+            int storelen;
+        } strings;
+        struct {
+            long long int *store;
+        } integers;
+        struct {
+            long long unsigned int *store;
+        } uintegers;
+        struct {
+            double *store;
+        } reals;
+        struct {
+            bool *store;
+        } booleans;
+    } arr;
+    int *count;
+    int maxlen;
+};
+
+struct cbor_attr_t {
+    char *attribute;
+    CborAttrType type;
+    union {
+        long long int *integer;
+        long long unsigned int *uinteger;
+        double *real;
+        float *fval;
+        char *string;
+        bool *boolean;
+        struct byte_string {
+            uint8_t *data;
+            size_t *len;
+        } bytestring;
+        struct cbor_array_t array;
+        size_t offset;
+        struct cbor_attr_t *obj;
+    } addr;
+    union {
+        long long int integer;
+        double real;
+        bool boolean;
+        float fval;
+    } dflt;
+    size_t len;
+    bool nodefault;
+};
+
+/*
+ * Use the following macros to declare template initializers for
+ * CborAttrStructObjectType arrays. Writing the equivalents out by hand is
+ * error-prone.
+ *
+ * CBOR_STRUCT_OBJECT takes a structure name s, and a fieldname f in s.
+ *
+ * CBOR_STRUCT_ARRAY takes the name of a structure array, a pointer to a an
+ * initializer defining the subobject type, and the address of an integer to
+ * store the length in.
+ */
+#define CBORATTR_STRUCT_OBJECT(s, f)        .addr.offset = offsetof(s, f)
+#define CBORATTR_STRUCT_ARRAY(a, e, n)                                  \
+    .addr.array.element_type = CborAttrStructObjectType,                \
+    .addr.array.arr.objects.subtype = e,                                \
+    .addr.array.arr.objects.base = (char*)a,                            \
+    .addr.array.arr.objects.stride = sizeof(a[0]),                      \
+    .addr.array.count = n,                                              \
+    .addr.array.maxlen = (int)(sizeof(a)/sizeof(a[0]))
+
+#define CBORATTR_ATTR_UNNAMED (char *)(-1)
+
+int cbor_read_object(struct CborValue *, const struct cbor_attr_t *);
+int cbor_read_array(struct CborValue *, const struct cbor_array_t *);
+
+int cbor_read_flat_attrs(const uint8_t *data, int len,
+                         const struct cbor_attr_t *attrs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBORATTR_H */
+
diff --git a/cborattr/pkg.yml b/cborattr/pkg.yml
new file mode 100644
index 0000000..8495f95
--- /dev/null
+++ b/cborattr/pkg.yml
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: cborattr 
+pkg.description: CBOR encoding/decoding library 
+pkg.author: "Apache Mynewt <d...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+
+pkg.deps:
+    - "encoding/tinycbor"
+
+pkg.cflags.FLOAT_USER: -DFLOAT_SUPPORT
diff --git a/cborattr/src/cborattr.c b/cborattr/src/cborattr.c
new file mode 100644
index 0000000..46cdc23
--- /dev/null
+++ b/cborattr/src/cborattr.c
@@ -0,0 +1,423 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//#include <syscfg/syscfg.h>
+#include "cborattr/cborattr.h"
+#include "cbor.h"
+#include "cbor_buf_reader.h"
+
+#define CBORATTR_MAX_SIZE 512
+
+/* this maps a CborType to a matching CborAtter Type. The mapping is not
+ * one-to-one because of signedness of integers
+ * and therefore we need a function to do this trickery */
+static int
+valid_attr_type(CborType ct, CborAttrType at)
+{
+    switch (at) {
+    case CborAttrIntegerType:
+    case CborAttrUnsignedIntegerType:
+        if (ct == CborIntegerType) {
+            return 1;
+        }
+        break;
+    case CborAttrByteStringType:
+        if (ct == CborByteStringType) {
+            return 1;
+        }
+        break;
+    case CborAttrTextStringType:
+        if (ct == CborTextStringType) {
+            return 1;
+        }
+        break;
+    case CborAttrBooleanType:
+        if (ct == CborBooleanType) {
+            return 1;
+        }
+#if FLOAT_SUPPORT
+    case CborAttrFloatType:
+        if (ct == CborFloatType) {
+            return 1;
+        }
+        break;
+    case CborAttrDoubleType:
+        if (ct == CborDoubleType) {
+            return 1;
+        }
+        break;
+#endif
+    case CborAttrArrayType:
+        if (ct == CborArrayType) {
+            return 1;
+        }
+        break;
+    case CborAttrObjectType:
+        if (ct == CborMapType) {
+            return 1;
+        }
+        break;
+    case CborAttrNullType:
+        if (ct == CborNullType) {
+            return 1;
+        }
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+/* this function find the pointer to the memory location to
+  * write or read and attribute from the cbor_attr_r structure */
+static char *
+cbor_target_address(const struct cbor_attr_t *cursor,
+                    const struct cbor_array_t *parent, int offset)
+{
+    char *targetaddr = NULL;
+
+    if (parent == NULL || parent->element_type != CborAttrStructObjectType) {
+        /* ordinary case - use the address in the cursor structure */
+        switch (cursor->type) {
+        case CborAttrNullType:
+            targetaddr = NULL;
+            break;
+        case CborAttrIntegerType:
+            targetaddr = (char *)&cursor->addr.integer[offset];
+            break;
+        case CborAttrUnsignedIntegerType:
+            targetaddr = (char *)&cursor->addr.uinteger[offset];
+            break;
+#if FLOAT_SUPPORT
+        case CborAttrFloatType:
+            targetaddr = (char *)&cursor->addr.fval[offset];
+            break;
+        case CborAttrDoubleType:
+            targetaddr = (char *)&cursor->addr.real[offset];
+            break;
+#endif
+        case CborAttrByteStringType:
+            targetaddr = (char *) cursor->addr.bytestring.data;
+            break;
+        case CborAttrTextStringType:
+            targetaddr = cursor->addr.string;
+            break;
+        case CborAttrBooleanType:
+            targetaddr = (char *)&cursor->addr.boolean[offset];
+            break;
+        default:
+            targetaddr = NULL;
+            break;
+        }
+    } else {
+        /* tricky case - hacking a member in an array of structures */
+        targetaddr =
+            parent->arr.objects.base + (offset * parent->arr.objects.stride) +
+            cursor->addr.offset;
+    }
+    return targetaddr;
+}
+
+static int
+cbor_internal_read_object(CborValue *root_value,
+                          const struct cbor_attr_t *attrs,
+                          const struct cbor_array_t *parent,
+                          int offset)
+{
+    const struct cbor_attr_t *cursor, *best_match;
+    char attrbuf[CBORATTR_MAX_SIZE + 1];
+    void *lptr;
+    CborValue cur_value;
+    CborError err = 0;
+    size_t len;
+    CborType type = CborInvalidType;
+
+    /* stuff fields with defaults in case they're omitted in the JSON input */
+    for (cursor = attrs; cursor->attribute != NULL; cursor++) {
+        if (!cursor->nodefault) {
+            lptr = cbor_target_address(cursor, parent, offset);
+            if (lptr != NULL) {
+                switch (cursor->type) {
+                case CborAttrIntegerType:
+                    memcpy(lptr, &cursor->dflt.integer, sizeof(long long int));
+                    break;
+                case CborAttrUnsignedIntegerType:
+                    memcpy(lptr, &cursor->dflt.integer,
+                           sizeof(long long unsigned int));
+                    break;
+                case CborAttrBooleanType:
+                    memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
+                    break;
+#if FLOAT_SUPPORT
+                case CborAttrFloatType:
+                    memcpy(lptr, &cursor->dflt.fval, sizeof(float));
+                    break;
+                case CborAttrDoubleType:
+                    memcpy(lptr, &cursor->dflt.real, sizeof(double));
+                    break;
+#endif
+                default:
+                    break;
+                }
+            }
+        }
+    }
+
+    if (cbor_value_is_map(root_value)) {
+        err |= cbor_value_enter_container(root_value, &cur_value);
+    } else {
+        err |= CborErrorIllegalType;
+        return err;
+    }
+
+    /* contains key value pairs */
+    while (cbor_value_is_valid(&cur_value) && !err) {
+        /* get the attribute */
+        if (cbor_value_is_text_string(&cur_value)) {
+            if (cbor_value_calculate_string_length(&cur_value, &len) == 0) {
+                if (len > CBORATTR_MAX_SIZE) {
+                    err |= CborErrorDataTooLarge;
+                    break;
+                }
+                err |= cbor_value_copy_text_string(&cur_value, attrbuf, &len,
+                                                     NULL);
+            }
+
+            /* at least get the type of the next value so we can match the
+             * attribute name and type for a perfect match */
+            err |= cbor_value_advance(&cur_value);
+            if (cbor_value_is_valid(&cur_value)) {
+                type = cbor_value_get_type(&cur_value);
+            } else {
+                err |= CborErrorIllegalType;
+                break;
+            }
+        } else {
+            attrbuf[0] = '\0';
+            type = cbor_value_get_type(&cur_value);
+        }
+
+        /* find this attribute in our list */
+        best_match = NULL;
+        for (cursor = attrs; cursor->attribute != NULL; cursor++) {
+            if (valid_attr_type(type, cursor->type)) {
+                if (cursor->attribute == CBORATTR_ATTR_UNNAMED &&
+                    attrbuf[0] == '\0') {
+                    best_match = cursor;
+                } else if (strlen(cursor->attribute) == len &&
+                    !memcmp(cursor->attribute, attrbuf, len)) {
+                    break;
+                }
+            }
+        }
+        if (!cursor->attribute && best_match) {
+            cursor = best_match;
+        }
+        /* we found a match */
+        if (cursor->attribute != NULL) {
+            lptr = cbor_target_address(cursor, parent, offset);
+            switch (cursor->type) {
+            case CborAttrNullType:
+                /* nothing to do */
+                break;
+            case CborAttrBooleanType:
+                err |= cbor_value_get_boolean(&cur_value, lptr);
+                break;
+            case CborAttrIntegerType:
+                err |= cbor_value_get_int64(&cur_value, lptr);
+                break;
+            case CborAttrUnsignedIntegerType:
+                err |= cbor_value_get_uint64(&cur_value, lptr);
+                break;
+#if FLOAT_SUPPORT
+            case CborAttrFloatType:
+                err |= cbor_value_get_float(&cur_value, lptr);
+                break;
+            case CborAttrDoubleType:
+                err |= cbor_value_get_double(&cur_value, lptr);
+                break;
+#endif
+            case CborAttrByteStringType: {
+                size_t len = cursor->len;
+                err |= cbor_value_copy_byte_string(&cur_value, lptr,
+                                                   &len, NULL);
+                *cursor->addr.bytestring.len = len;
+                break;
+            }
+            case CborAttrTextStringType: {
+                size_t len = cursor->len;
+                err |= cbor_value_copy_text_string(&cur_value, lptr,
+                                                   &len, NULL);
+                break;
+            }
+            case CborAttrArrayType:
+                err |= cbor_read_array(&cur_value, &cursor->addr.array);
+                continue;
+            case CborAttrObjectType:
+                err |= cbor_internal_read_object(&cur_value, cursor->addr.obj,
+                                                 NULL, 0);
+                continue;
+            default:
+                err |= CborErrorIllegalType;
+            }
+        }
+        cbor_value_advance(&cur_value);
+    }
+    if (!err) {
+        /* that should be it for this container */
+        err |= cbor_value_leave_container(root_value, &cur_value);
+    }
+    return err;
+}
+
+int
+cbor_read_array(struct CborValue *value, const struct cbor_array_t *arr)
+{
+    CborError err = 0;
+    struct CborValue elem;
+    int off, arrcount;
+    size_t len;
+    void *lptr;
+    char *tp;
+
+    err = cbor_value_enter_container(value, &elem);
+    if (err) {
+        return err;
+    }
+    arrcount = 0;
+    tp = arr->arr.strings.store;
+    for (off = 0; off < arr->maxlen; off++) {
+        switch (arr->element_type) {
+        case CborAttrBooleanType:
+            lptr = &arr->arr.booleans.store[off];
+            err |= cbor_value_get_boolean(&elem, lptr);
+            break;
+        case CborAttrIntegerType:
+            lptr = &arr->arr.integers.store[off];
+            err |= cbor_value_get_int64(&elem, lptr);
+            break;
+        case CborAttrUnsignedIntegerType:
+            lptr = &arr->arr.uintegers.store[off];
+            err |= cbor_value_get_uint64(&elem, lptr);
+            break;
+#if FLOAT_SUPPORT
+        case CborAttrFloatType:
+        case CborAttrDoubleType:
+            lptr = &arr->arr.reals.store[off];
+            err |= cbor_value_get_double(&elem, lptr);
+            break;
+#endif
+        case CborAttrTextStringType:
+            len = arr->arr.strings.storelen - (tp - arr->arr.strings.store);
+            err |= cbor_value_copy_text_string(&elem, tp, &len, NULL);
+            arr->arr.strings.ptrs[off] = tp;
+            tp += len + 1;
+            break;
+        case CborAttrStructObjectType:
+            err |= cbor_internal_read_object(&elem, arr->arr.objects.subtype,
+                                             arr, off);
+            break;
+        default:
+            err |= CborErrorIllegalType;
+            break;
+        }
+        arrcount++;
+        if (arr->element_type != CborAttrStructObjectType) {
+            err |= cbor_value_advance(&elem);
+        }
+        if (!cbor_value_is_valid(&elem)) {
+            break;
+        }
+    }
+    if (arr->count) {
+        *arr->count = arrcount;
+    }
+    while (!cbor_value_at_end(&elem)) {
+        err |= CborErrorDataTooLarge;
+        cbor_value_advance(&elem);
+    }
+    err |= cbor_value_leave_container(value, &elem);
+    return err;
+}
+
+int
+cbor_read_object(struct CborValue *value, const struct cbor_attr_t *attrs)
+{
+    int st;
+
+    st = cbor_internal_read_object(value, attrs, NULL, 0);
+    return st;
+}
+
+/*
+ * Read in cbor key/values from flat buffer pointed by data, and fill them
+ * into attrs.
+ *
+ * @param data         Pointer to beginning of cbor encoded data
+ * @param len          Number of bytes in the buffer
+ * @param attrs                Array of cbor objects to look for.
+ *
+ * @return             0 on success; non-zero on failure.
+ */
+int
+cbor_read_flat_attrs(const uint8_t *data, int len,
+                     const struct cbor_attr_t *attrs)
+{
+    struct cbor_buf_reader reader;
+    struct CborParser parser;
+    struct CborValue value;
+    CborError err;
+
+    cbor_buf_reader_init(&reader, data, len);
+    err = cbor_parser_cust_reader_init(&reader.r, 0, &parser, &value);
+    if (err != CborNoError) {
+        return -1;
+    }
+    return cbor_read_object(&value, attrs);
+}
+
+#if 0
+/*
+ * Read in cbor key/values from os_mbuf pointed by m, and fill them
+ * into attrs.
+ *
+ * @param m            Pointer to os_mbuf containing cbor encoded data
+ * @param off          Offset into mbuf where cbor data begins
+ * @param len          Number of bytes to decode
+ * @param attrs                Array of cbor objects to look for.
+ *
+ * @return             0 on success; non-zero on failure.
+ */
+int
+cbor_read_mbuf_attrs(struct os_mbuf *m, uint16_t off, uint16_t len,
+                     const struct cbor_attr_t *attrs)
+{
+    struct cbor_mbuf_reader cmr;
+    struct CborParser parser;
+    struct CborValue value;
+    CborError err;
+
+    cbor_mbuf_reader_init(&cmr, m, off);
+    err = cbor_parser_init(&cmr.r, 0, &parser, &value);
+    if (err != CborNoError) {
+        return -1;
+    }
+    return cbor_read_object(&value, attrs);
+}
+#endif
diff --git a/cborattr/syscfg.yml b/cborattr/syscfg.yml
new file mode 100644
index 0000000..cc93c26
--- /dev/null
+++ b/cborattr/syscfg.yml
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Package: mgmt/imgmgr
+
+syscfg.defs:
+    CBORATTR_MAX_SIZE:
+        description: 'The maximum size of a CBOR attribute during decoding'
+        value: 512
diff --git a/cborattr/test/pkg.yml b/cborattr/test/pkg.yml
new file mode 100644
index 0000000..071ca5f
--- /dev/null
+++ b/cborattr/test/pkg.yml
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+pkg.name: cborattr/test
+pkg.type: unittest
+pkg.description: "CBOR attr unit tests."
+pkg.author: "Apache Mynewt <d...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+
+pkg.deps:
+    - '@mynewt-mcumgr/ext/tinycbor'
+    - '@mynewt-mcumgr/cborattr'
+
+pkg.deps.SELFTEST:
+    - sys/console/stub
diff --git a/cborattr/test/src/test_cborattr.c 
b/cborattr/test/src/test_cborattr.c
new file mode 100644
index 0000000..0a64039
--- /dev/null
+++ b/cborattr/test/src/test_cborattr.c
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "testutil/testutil.h"
+#include "test_cborattr.h"
+
+TEST_SUITE(test_cborattr_suite)
+{
+    test_cborattr_decode1();
+    test_cborattr_decode_partial();
+    test_cborattr_decode_simple();
+    test_cborattr_decode_object();
+    test_cborattr_decode_int_array();
+    test_cborattr_decode_bool_array();
+    test_cborattr_decode_string_array();
+    test_cborattr_decode_object_array();
+    test_cborattr_decode_unnamed_array();
+    test_cborattr_decode_substring_key();
+}
+
+#if MYNEWT_VAL(SELFTEST)
+int
+main(int argc, char **argv)
+{
+    sysinit();
+
+    test_cborattr_suite();
+
+    return tu_any_failed;
+}
+#endif
diff --git a/cborattr/test/src/test_cborattr.h 
b/cborattr/test/src/test_cborattr.h
new file mode 100644
index 0000000..815048f
--- /dev/null
+++ b/cborattr/test/src/test_cborattr.h
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef TEST_CBORATTR_H
+#define TEST_CBORATTR_H
+
+#include <assert.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "test_cborattr.h"
+#include "tinycbor/cbor.h"
+#include "cborattr/cborattr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Returns test data.
+ */
+const uint8_t *test_str1(int *len);
+
+/*
+ * Testcases
+ */
+TEST_CASE_DECL(test_cborattr_decode1);
+TEST_CASE_DECL(test_cborattr_decode_partial);
+TEST_CASE_DECL(test_cborattr_decode_simple);
+TEST_CASE_DECL(test_cborattr_decode_object);
+TEST_CASE_DECL(test_cborattr_decode_int_array);
+TEST_CASE_DECL(test_cborattr_decode_bool_array);
+TEST_CASE_DECL(test_cborattr_decode_string_array);
+TEST_CASE_DECL(test_cborattr_decode_object_array);
+TEST_CASE_DECL(test_cborattr_decode_unnamed_array);
+TEST_CASE_DECL(test_cborattr_decode_substring_key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_CBORATTR_H */
+
diff --git a/cborattr/test/src/test_cborattr_utils.c 
b/cborattr/test/src/test_cborattr_utils.c
new file mode 100644
index 0000000..0a43766
--- /dev/null
+++ b/cborattr/test/src/test_cborattr_utils.c
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_cborattr.h"
+/*
+ * {"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
+ */
+static const uint8_t test_data1[] = {
+    0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61,
+    0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61,
+    0x44, 0x61, 0x65, 0x61, 0x45
+};
+
+const uint8_t *
+test_str1(int *len)
+{
+    *len = sizeof(test_data1);
+    return (test_data1);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode1.c 
b/cborattr/test/src/testcases/cborattr_decode1.c
new file mode 100644
index 0000000..1b6cddf
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode1.c
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode1)
+{
+    const uint8_t *data;
+    int len;
+    int rc;
+    char test_str_a[4] = { '\0' };
+    char test_str_b[4] = { '\0' };
+    char test_str_c[4] = { '\0' };
+    char test_str_d[4] = { '\0' };
+    char test_str_e[4] = { '\0' };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_a,
+            .len = sizeof(test_str_a),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_b,
+            .len = sizeof(test_str_b),
+            .nodefault = true
+            },
+        [2] = {
+            .attribute = "c",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_c,
+            .len = sizeof(test_str_c),
+            .nodefault = true
+            },
+        [3] = {
+            .attribute = "d",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_d,
+            .len = sizeof(test_str_d),
+            .nodefault = true,
+            },
+        [4] = {
+            .attribute = "e",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_e,
+            .len = sizeof(test_str_e),
+            .nodefault = true,
+        },
+        [5] = {
+            .attribute = NULL
+        }
+    };
+
+    data = test_str1(&len);
+    rc = cbor_read_flat_attrs(data, len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!strcmp(test_str_a, "A"));
+    TEST_ASSERT(!strcmp(test_str_b, "B"));
+    TEST_ASSERT(!strcmp(test_str_c, "C"));
+    TEST_ASSERT(!strcmp(test_str_d, "D"));
+    TEST_ASSERT(!strcmp(test_str_e, "E"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_bool_array.c 
b/cborattr/test/src/testcases/cborattr_decode_bool_array.c
new file mode 100644
index 0000000..71520c4
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_bool_array.c
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_bool_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [true,true,false]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_boolean(&array, true);
+    cbor_encode_boolean(&array, true);
+    cbor_encode_boolean(&array, false);
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * array of booleans
+ */
+TEST_CASE(test_cborattr_decode_bool_array)
+{
+    int rc;
+    bool arr_data[5];
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrBooleanType,
+            .addr.array.arr.booleans.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_bool_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(arr_data[0] == true);
+    TEST_ASSERT(arr_data[1] == true);
+    TEST_ASSERT(arr_data[2] == false);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_int_array.c 
b/cborattr/test/src/testcases/cborattr_decode_int_array.c
new file mode 100644
index 0000000..96bc8cc
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_int_array.c
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_int_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [1,2,33,15,-4]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_int(&array, 1);
+    cbor_encode_int(&array, 2);
+    cbor_encode_int(&array, 33);
+    cbor_encode_int(&array, 15);
+    cbor_encode_int(&array, -4);
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * integer array
+ */
+TEST_CASE(test_cborattr_decode_int_array)
+{
+    int rc;
+    int64_t arr_data[5];
+    int64_t b_int;
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrIntegerType,
+            .addr.array.arr.integers.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrIntegerType,
+            .addr.integer = &b_int,
+            .dflt.integer = 1
+        },
+        [2] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attrs_small[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrIntegerType,
+            .addr.array.arr.integers.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = 1,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrIntegerType,
+            .addr.integer = &b_int,
+            .dflt.integer = 1
+        },
+        [2] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_int_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 5);
+    TEST_ASSERT(arr_data[0] == 1);
+    TEST_ASSERT(arr_data[1] == 2);
+    TEST_ASSERT(arr_data[2] == 33);
+    TEST_ASSERT(arr_data[3] == 15);
+    TEST_ASSERT(arr_data[4] == -4);
+    TEST_ASSERT(b_int == 1);
+
+    memset(arr_data, 0, sizeof(arr_data));
+    b_int = 0;
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs_small);
+    TEST_ASSERT(rc == CborErrorDataTooLarge);
+    TEST_ASSERT(arr_cnt == 1);
+    TEST_ASSERT(arr_data[0] == 1);
+    TEST_ASSERT(arr_data[1] == 0);
+    TEST_ASSERT(b_int == 1);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_obj_array.c 
b/cborattr/test/src/testcases/cborattr_decode_obj_array.c
new file mode 100644
index 0000000..57c46cd
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_obj_array.c
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_obj_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+    CborEncoder obj;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [{ n:"a", v:1}, {n:"b", v:2} ]
+     */
+    cbor_encode_text_stringz(&data, "a");
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+
+    cbor_encoder_create_map(&array, &obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&obj, "n");
+    cbor_encode_text_stringz(&obj, "a");
+    cbor_encode_text_stringz(&obj, "v");
+    cbor_encode_int(&obj, 1);
+    cbor_encoder_close_container(&array, &obj);
+
+    cbor_encoder_create_map(&array, &obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&obj, "n");
+    cbor_encode_text_stringz(&obj, "b");
+    cbor_encode_text_stringz(&obj, "v");
+    cbor_encode_int(&obj, 2);
+    cbor_encoder_close_container(&array, &obj);
+
+    cbor_encoder_close_container(&data, &array);
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * object array
+ */
+TEST_CASE(test_cborattr_decode_obj_array)
+{
+    int rc;
+    char arr_data[4];
+    int arr_cnt;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrNullType,
+            .addr.array.arr.objects.base = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = 4,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_obj_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 2);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_object.c 
b/cborattr/test/src/testcases/cborattr_decode_object.c
new file mode 100644
index 0000000..25a32d2
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_object.c
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_data(void)
+{
+    CborEncoder test_data;
+    CborEncoder sub_obj;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+    cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+
+    /*
+     * p: { bm : 7 }
+     */
+    cbor_encode_text_stringz(&test_data, "p");
+
+    cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&test_data, "bm");
+    cbor_encode_int(&test_data, 7);
+    cbor_encoder_close_container(&test_data, &sub_obj);
+
+    cbor_encoder_close_container(&test_encoder, &test_data);
+}
+
+static void
+test_encode_data_complex(void)
+{
+    CborEncoder test_data;
+    CborEncoder sub_obj;
+    CborEncoder sub_sub_obj;
+
+    test_cbor_len = 0;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+    cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+
+    /*
+     * p: { bm : 7 }, c: { d : { i : 1 } }, a: 3
+     */
+    cbor_encode_text_stringz(&test_data, "p");
+
+    cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&test_data, "bm");
+    cbor_encode_int(&test_data, 7);
+    cbor_encoder_close_container(&test_data, &sub_obj);
+
+    cbor_encode_text_stringz(&test_data, "c");
+    cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "d");
+
+    cbor_encoder_create_map(&sub_obj, &sub_sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_sub_obj, "i");
+    cbor_encode_int(&sub_sub_obj, 1);
+    cbor_encoder_close_container(&sub_obj, &sub_sub_obj);
+    cbor_encoder_close_container(&test_data, &sub_obj);
+
+    cbor_encode_text_stringz(&test_data, "a");
+    cbor_encode_int(&test_data, 3);
+
+    cbor_encoder_close_container(&test_encoder, &test_data);
+}
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode_object)
+{
+    int rc;
+    int64_t bm_val = 0;
+    struct cbor_attr_t test_sub_attr_bm[] = {
+        [0] = {
+            .attribute = "bm",
+            .type = CborAttrIntegerType,
+            .addr.integer = &bm_val,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "p",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_attr_bm,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    int64_t a_val = 0;
+    int64_t i_val = 0;
+    struct cbor_attr_t test_sub_sub_attr[] = {
+        [0] = {
+            .attribute = "i",
+            .type = CborAttrIntegerType,
+            .addr.integer = &i_val,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_sub_attr_d[] = {
+        [0] = {
+            .attribute = "d",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_sub_attr,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attr_complex[] = {
+        [0] = {
+            .attribute = "c",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_attr_d,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "a",
+            .type = CborAttrIntegerType,
+            .addr.integer = &a_val,
+            .nodefault = true
+        },
+        [2] = {
+            .attribute = "p",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_attr_bm,
+            .nodefault = true
+        },
+        [3] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_data();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(bm_val == 7);
+
+    test_encode_data_complex();
+
+    bm_val = 0;
+    i_val = 0;
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attr_complex);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(bm_val == 7);
+    TEST_ASSERT(i_val == 1);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_object_array.c 
b/cborattr/test/src/testcases/cborattr_decode_object_array.c
new file mode 100644
index 0000000..82cc34f
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_object_array.c
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_object_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+    CborEncoder sub_obj;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [ { h:"str1"}, {h:"2str"}, {h:"str3"}]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+
+    cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "h");
+    cbor_encode_text_stringz(&sub_obj, "str1");
+    cbor_encoder_close_container(&array, &sub_obj);
+
+    cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "h");
+    cbor_encode_text_stringz(&sub_obj, "2str");
+    cbor_encoder_close_container(&array, &sub_obj);
+
+    cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "h");
+    cbor_encode_text_stringz(&sub_obj, "str3");
+    cbor_encoder_close_container(&array, &sub_obj);
+
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * object array
+ */
+TEST_CASE(test_cborattr_decode_object_array)
+{
+    int rc;
+    struct h_obj {
+        char h_data[32];
+    } arr_objs[5];
+    int arr_cnt = 0;
+    struct cbor_attr_t sub_attr[] = {
+        [0] = {
+            .attribute = "h",
+            .type = CborAttrTextStringType,
+            CBORATTR_STRUCT_OBJECT(struct h_obj, h_data),
+            .len = sizeof(arr_objs[0].h_data)
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            CBORATTR_STRUCT_ARRAY(arr_objs, sub_attr, &arr_cnt),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_object_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(!strcmp(arr_objs[0].h_data, "str1"));
+    TEST_ASSERT(!strcmp(arr_objs[1].h_data, "2str"));
+    TEST_ASSERT(!strcmp(arr_objs[2].h_data, "str3"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_partial.c 
b/cborattr/test/src/testcases/cborattr_decode_partial.c
new file mode 100644
index 0000000..df0b8d4
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_partial.c
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Simple decoding. Only have key for one of the key/value pairs.
+ */
+TEST_CASE(test_cborattr_decode_partial)
+{
+    const uint8_t *data;
+    int len;
+    int rc;
+    char test_str_b[4] = { '\0' };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "b",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_b,
+            .len = sizeof(test_str_b),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    data = test_str1(&len);
+    rc = cbor_read_flat_attrs(data, len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!strcmp(test_str_b, "B"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_simple.c 
b/cborattr/test/src/testcases/cborattr_decode_simple.c
new file mode 100644
index 0000000..9e206e1
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_simple.c
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_data(void)
+{
+    CborEncoder test_data;
+    uint8_t data[4] = { 0, 1, 2 };
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+    /*
+     * a:22
+     */
+    cbor_encode_text_stringz(&test_data, "a");
+    cbor_encode_uint(&test_data, 22);
+
+    /*
+     * b:-13
+     */
+    cbor_encode_text_stringz(&test_data, "b");
+    cbor_encode_int(&test_data, -13);
+
+    /*
+     * c:0x000102
+     */
+    cbor_encode_text_stringz(&test_data, "c");
+    cbor_encode_byte_string(&test_data, data, 3);
+    cbor_encoder_close_container(&test_encoder, &test_data);
+
+    /*
+     * XXX add other data types to encode here.
+     */
+
+}
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode_simple)
+{
+    int rc;
+    uint64_t a_val = 0;
+    int64_t b_val = 0;
+    uint8_t c_data[4];
+    size_t c_len;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrIntegerType,
+            .addr.uinteger = &a_val,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrIntegerType,
+            .addr.integer = &b_val,
+            .nodefault = true
+        },
+        [2] = {
+            .attribute = "c",
+            .type = CborAttrByteStringType,
+            .addr.bytestring.data = c_data,
+            .addr.bytestring.len = &c_len,
+            .len = sizeof(c_data)
+        },
+        [3] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_data();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(a_val == 22);
+    TEST_ASSERT(b_val == -13);
+    TEST_ASSERT(c_len == 3);
+    TEST_ASSERT(c_data[0] == 0 && c_data[1] == 1 && c_data[2] == 2);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_string_array.c 
b/cborattr/test/src/testcases/cborattr_decode_string_array.c
new file mode 100644
index 0000000..d68e8df
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_string_array.c
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_string_array_one(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: ["asdf"]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_text_stringz(&array, "asdf");
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+static void
+test_encode_string_array_three(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: ["asdf", "k", "blurb"]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_text_stringz(&array, "asdf");
+    cbor_encode_text_stringz(&array, "k");
+    cbor_encode_text_stringz(&array, "blurb");
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * string array
+ */
+TEST_CASE(test_cborattr_decode_string_array)
+{
+    int rc;
+    char *str_ptrs[5];
+    char arr_data[256];
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrTextStringType,
+            .addr.array.arr.strings.ptrs = str_ptrs,
+            .addr.array.arr.strings.store = arr_data,
+            .addr.array.arr.strings.storelen = sizeof(arr_data),
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_string_array_one();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 1);
+    TEST_ASSERT(!strcmp(str_ptrs[0], "asdf"));
+
+    test_encode_string_array_three();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(!strcmp(str_ptrs[0], "asdf"));
+    TEST_ASSERT(!strcmp(str_ptrs[1], "k"));
+    TEST_ASSERT(!strcmp(str_ptrs[2], "blurb"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_substring_key.c 
b/cborattr/test/src/testcases/cborattr_decode_substring_key.c
new file mode 100644
index 0000000..6eee774
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_substring_key.c
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_substring_key(void)
+{
+    CborEncoder data;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    /*
+     * { "a": "A", "aa": "AA", "aaa" : "AAA" }
+     */
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    cbor_encode_text_stringz(&data, "a");
+    cbor_encode_text_stringz(&data, "A");
+    cbor_encode_text_stringz(&data, "aa");
+    cbor_encode_text_stringz(&data, "AA");
+    cbor_encode_text_stringz(&data, "aaa");
+    cbor_encode_text_stringz(&data, "AAA");
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * substring key
+ */
+TEST_CASE(test_cborattr_decode_substring_key)
+{
+    int rc;
+    char test_str_1a[4] = { '\0' };
+    char test_str_2a[4] = { '\0' };
+    char test_str_3a[4] = { '\0' };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "aaa",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_3a,
+            .len = sizeof(test_str_3a),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "aa",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_2a,
+            .len = sizeof(test_str_2a),
+            .nodefault = true
+            },
+        [2] = {
+            .attribute = "a",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_1a,
+            .len = sizeof(test_str_1a),
+            .nodefault = true
+            },
+        [3] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_substring_key();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!strcmp(test_str_1a, "A"));
+    TEST_ASSERT(!strcmp(test_str_2a, "AA"));
+    TEST_ASSERT(!strcmp(test_str_3a, "AAA"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c 
b/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c
new file mode 100644
index 0000000..c4446b8
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_unnamed_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * [1,2,33]
+     */
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_int(&array, 1);
+    cbor_encode_int(&array, 2);
+    cbor_encode_int(&array, 33);
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * integer array
+ */
+TEST_CASE(test_cborattr_decode_unnamed_array)
+{
+    int rc;
+    int64_t arr_data[5];
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = CBORATTR_ATTR_UNNAMED,
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrIntegerType,
+            .addr.array.arr.integers.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_unnamed_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(arr_data[0] == 1);
+    TEST_ASSERT(arr_data[1] == 2);
+    TEST_ASSERT(arr_data[2] == 33);
+}

-- 
To stop receiving notification emails like this one, please contact
ccoll...@apache.org.

Reply via email to