http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/net/ip/mn_socket/test/src/mn_sock_util.c
----------------------------------------------------------------------
diff --git a/net/ip/mn_socket/test/src/mn_sock_util.c 
b/net/ip/mn_socket/test/src/mn_sock_util.c
new file mode 100644
index 0000000..19ffe71
--- /dev/null
+++ b/net/ip/mn_socket/test/src/mn_sock_util.c
@@ -0,0 +1,775 @@
+/**
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "os/os.h"
+#include "testutil/testutil.h"
+
+#include "mn_socket/mn_socket.h"
+#include "mn_socket/arch/sim/native_sock.h"
+
+struct os_sem test_sem;
+
+void
+sock_open_close(void)
+{
+    struct mn_socket *sock;
+    int rc;
+
+    rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(sock);
+    TEST_ASSERT(rc == 0);
+    mn_close(sock);
+
+    rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(sock);
+    TEST_ASSERT(rc == 0);
+    mn_close(sock);
+
+    rc = mn_socket(&sock, MN_PF_INET6, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(sock);
+    TEST_ASSERT(rc == 0);
+    mn_close(sock);
+
+    rc = mn_socket(&sock, MN_PF_INET6, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(sock);
+    TEST_ASSERT(rc == 0);
+    mn_close(sock);
+}
+
+void
+sock_listen(void)
+{
+    struct mn_socket *sock;
+    struct mn_sockaddr_in msin;
+    int rc;
+
+    rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    msin.msin_family = MN_PF_INET;
+    msin.msin_len = sizeof(msin);
+    msin.msin_port = htons(12444);
+
+    mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr);
+
+    rc = mn_bind(sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_listen(sock, 2);
+    TEST_ASSERT(rc == 0);
+
+    mn_close(sock);
+}
+
+void
+stc_writable(void *cb_arg, int err)
+{
+    int *i;
+
+    TEST_ASSERT(err == 0);
+    i = (int *)cb_arg;
+    *i = *i + 1;
+}
+
+int
+stc_newconn(void *cb_arg, struct mn_socket *new)
+{
+    struct mn_socket **r_sock;
+
+    r_sock = cb_arg;
+    *r_sock = new;
+
+    os_sem_release(&test_sem);
+    return 0;
+}
+
+void
+sock_tcp_connect(void)
+{
+    struct mn_socket *listen_sock;
+    struct mn_socket *sock;
+    struct mn_sockaddr_in msin;
+    struct mn_sockaddr_in msin2;
+    int rc;
+    union mn_socket_cb listen_cbs = {
+        .listen.newconn = stc_newconn,
+    };
+    union mn_socket_cb sock_cbs = {
+        .socket.writable = stc_writable
+    };
+    int connected = 0;
+    struct mn_socket *new_sock = NULL;
+
+    rc = mn_socket(&listen_sock, MN_PF_INET, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    msin.msin_family = MN_PF_INET;
+    msin.msin_len = sizeof(msin);
+    msin.msin_port = htons(12445);
+
+    mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr);
+
+    mn_socket_set_cbs(listen_sock, &new_sock, &listen_cbs);
+    rc = mn_bind(listen_sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_listen(listen_sock, 2);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    mn_socket_set_cbs(sock, &connected, &sock_cbs);
+
+    rc = mn_connect(sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(connected == 1);
+    TEST_ASSERT(new_sock != NULL);
+
+    /*
+     * Check endpoint data matches
+     */
+    rc = mn_getsockname(sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+    rc = mn_getpeername(new_sock, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!memcmp(&msin, &msin2, sizeof(msin)));
+
+    rc = mn_getsockname(new_sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+    rc = mn_getpeername(sock, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!memcmp(&msin, &msin2, sizeof(msin)));
+
+
+    if (new_sock) {
+        mn_close(new_sock);
+    }
+    mn_close(sock);
+    mn_close(listen_sock);
+}
+
+void
+sud_readable(void *cb_arg, int err)
+{
+    os_sem_release(&test_sem);
+}
+
+void
+sock_udp_data(void)
+{
+    struct mn_socket *sock1;
+    struct mn_socket *sock2;
+    struct mn_sockaddr_in msin;
+    struct mn_sockaddr_in msin2;
+    int rc;
+    union mn_socket_cb sock_cbs = {
+        .socket.readable = sud_readable
+    };
+    struct os_mbuf *m;
+    char data[] = "1234567890";
+
+    rc = mn_socket(&sock1, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(sock1, NULL, &sock_cbs);
+
+    rc = mn_socket(&sock2, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(sock2, NULL, &sock_cbs);
+
+    msin.msin_family = MN_PF_INET;
+    msin.msin_len = sizeof(msin);
+    msin.msin_port = htons(12445);
+
+    mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr);
+
+    rc = mn_bind(sock1, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    msin2.msin_family = MN_PF_INET;
+    msin2.msin_len = sizeof(msin2);
+    msin2.msin_port = 0;
+    msin2.msin_addr.s_addr = 0;
+    rc = mn_bind(sock2, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    TEST_ASSERT(m);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+    rc = mn_sendto(sock2, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * Wait for the packet.
+     */
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_recvfrom(sock1, &m, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+    TEST_ASSERT(msin2.msin_family == MN_AF_INET);
+    TEST_ASSERT(msin2.msin_len == sizeof(msin2));
+    TEST_ASSERT(msin2.msin_port != 0);
+    TEST_ASSERT(msin2.msin_addr.s_addr != 0);
+
+    if (m) {
+        TEST_ASSERT(OS_MBUF_IS_PKTHDR(m));
+        TEST_ASSERT(OS_MBUF_PKTLEN(m) == sizeof(data));
+        TEST_ASSERT(m->om_len == sizeof(data));
+        TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data)));
+    }
+
+    rc = mn_sendto(sock1, m, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_recvfrom(sock2, &m, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+    if (m) {
+        TEST_ASSERT(OS_MBUF_IS_PKTHDR(m));
+        TEST_ASSERT(OS_MBUF_PKTLEN(m) == sizeof(data));
+        TEST_ASSERT(m->om_len == sizeof(data));
+        TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data)));
+        os_mbuf_free_chain(m);
+    }
+
+    mn_close(sock1);
+    mn_close(sock2);
+}
+
+void
+std_writable(void *cb_arg, int err)
+{
+    int *i;
+
+    TEST_ASSERT(err == 0);
+    i = (int *)cb_arg;
+    if (i) {
+        *i = *i + 1;
+    }
+}
+
+void
+std_readable(void *cb_arg, int err)
+{
+    os_sem_release(&test_sem);
+}
+
+static union mn_socket_cb sud_sock_cbs = {
+    .socket.writable = std_writable,
+    .socket.readable = std_readable
+};
+
+int
+std_newconn(void *cb_arg, struct mn_socket *new)
+{
+    struct mn_socket **r_sock;
+
+    r_sock = cb_arg;
+    *r_sock = new;
+
+    mn_socket_set_cbs(new, NULL, &sud_sock_cbs);
+
+    os_sem_release(&test_sem);
+    return 0;
+}
+
+void
+sock_tcp_data(void)
+{
+    struct mn_socket *listen_sock;
+    struct mn_socket *sock;
+    struct mn_sockaddr_in msin;
+    int rc;
+    union mn_socket_cb listen_cbs = {
+        .listen.newconn = std_newconn,
+    };
+    int connected = 0;
+    struct mn_socket *new_sock = NULL;
+    struct os_mbuf *m;
+    char data[] = "1234567890";
+
+    rc = mn_socket(&listen_sock, MN_PF_INET, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    msin.msin_family = MN_PF_INET;
+    msin.msin_len = sizeof(msin);
+    msin.msin_port = htons(12447);
+
+    mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr);
+
+    mn_socket_set_cbs(listen_sock, &new_sock, &listen_cbs);
+    rc = mn_bind(listen_sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_listen(listen_sock, 2);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    mn_socket_set_cbs(sock, &connected, &sud_sock_cbs);
+
+    rc = mn_connect(sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(connected == 1);
+    TEST_ASSERT(new_sock != NULL);
+
+    m = os_msys_get(sizeof(data), 0);
+    TEST_ASSERT(m);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+    rc = mn_sendto(new_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * Wait for the packet.
+     */
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    memset(&msin, 0, sizeof(msin));
+    rc = mn_recvfrom(sock, &m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+    TEST_ASSERT(msin.msin_family == MN_AF_INET);
+    TEST_ASSERT(msin.msin_len == sizeof(msin));
+    TEST_ASSERT(msin.msin_port != 0);
+    TEST_ASSERT(msin.msin_addr.s_addr != 0);
+    os_mbuf_free_chain(m);
+
+    if (new_sock) {
+        mn_close(new_sock);
+    }
+    mn_close(sock);
+    mn_close(listen_sock);
+}
+
+void
+sock_itf_list(void)
+{
+    struct mn_itf itf;
+    struct mn_itf_addr itf_addr;
+    int if_cnt = 0;
+    int seen_127;
+    struct mn_in_addr addr127;
+    char addr_str[64];
+    int rc;
+
+    mn_inet_pton(MN_PF_INET, "127.0.0.1", &addr127);
+
+    memset(&itf, 0, sizeof(itf));
+
+    while (1) {
+        rc = mn_itf_getnext(&itf);
+        if (rc) {
+            break;
+        }
+        printf("%d: %x %s\n", itf.mif_idx, itf.mif_flags, itf.mif_name);
+        memset(&itf_addr, 0, sizeof(itf_addr));
+        while (1) {
+            rc = mn_itf_addr_getnext(&itf, &itf_addr);
+            if (rc) {
+                break;
+            }
+            if (itf_addr.mifa_family == MN_AF_INET &&
+              !memcmp(&itf_addr.mifa_addr, &addr127, sizeof(addr127))) {
+                seen_127 = 1;
+            }
+            addr_str[0] = '\0';
+            mn_inet_ntop(itf_addr.mifa_family, &itf_addr.mifa_addr,
+              addr_str, sizeof(addr_str));
+            printf(" %s/%d\n", addr_str, itf_addr.mifa_plen);
+        }
+        if_cnt++;
+    }
+    TEST_ASSERT(if_cnt > 0);
+    TEST_ASSERT(seen_127);
+}
+
+static int
+first_ll_addr(struct mn_sockaddr_in6 *ra)
+{
+    struct mn_itf itf;
+    struct mn_itf_addr itf_addr;
+    int rc;
+    struct mn_in6_addr *addr;
+
+    memset(&itf, 0, sizeof(itf));
+    addr = (struct mn_in6_addr *)&itf_addr.mifa_addr;
+    while (1) {
+        rc = mn_itf_getnext(&itf);
+        if (rc) {
+            break;
+        }
+        memset(&itf_addr, 0, sizeof(itf_addr));
+        while (1) {
+            rc = mn_itf_addr_getnext(&itf, &itf_addr);
+            if (rc) {
+                break;
+            }
+            if (itf_addr.mifa_family == MN_AF_INET6 &&
+              addr->s_addr[0] == 0xfe && addr->s_addr[1] == 0x80) {
+                memset(ra, 0, sizeof(*ra));
+                ra->msin6_family = MN_AF_INET6;
+                ra->msin6_len = sizeof(*ra);
+                ra->msin6_scope_id = itf.mif_idx;
+                memcpy(&ra->msin6_addr, addr, sizeof(*addr));
+                return 0;
+            }
+        }
+    }
+    return -1;
+}
+
+void
+sul_readable(void *cb_arg, int err)
+{
+    os_sem_release(&test_sem);
+}
+
+void
+sock_udp_ll(void)
+{
+    struct mn_socket *sock1;
+    struct mn_socket *sock2;
+    struct mn_sockaddr_in6 msin;
+    struct mn_sockaddr_in6 msin2;
+    int rc;
+    union mn_socket_cb sock_cbs = {
+        .socket.readable = sul_readable
+    };
+    struct os_mbuf *m;
+    char data[] = "1234567890";
+
+    rc = mn_socket(&sock1, MN_PF_INET6, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(sock1, NULL, &sock_cbs);
+
+    rc = mn_socket(&sock2, MN_PF_INET6, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(sock2, NULL, &sock_cbs);
+
+    rc = first_ll_addr(&msin);
+    if (rc != 0) {
+        printf("No ipv6 address present?\n");
+        return;
+    }
+    msin.msin6_port = htons(12445);
+
+    rc = mn_bind(sock1, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_getsockname(sock1, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    TEST_ASSERT(m);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+    rc = mn_sendto(sock2, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin2);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * Wait for the packet.
+     */
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_recvfrom(sock1, &m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+
+    if (m) {
+        TEST_ASSERT(OS_MBUF_IS_PKTHDR(m));
+        TEST_ASSERT(OS_MBUF_PKTLEN(m) == sizeof(data));
+        TEST_ASSERT(m->om_len == sizeof(data));
+        TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data)));
+        os_mbuf_free_chain(m);
+    }
+
+    mn_close(sock1);
+    mn_close(sock2);
+}
+
+static int
+sock_find_multicast_if(void)
+{
+    struct mn_itf itf;
+
+    memset(&itf, 0, sizeof(itf));
+
+    while (1) {
+        if (mn_itf_getnext(&itf)) {
+            break;
+        }
+        if ((itf.mif_flags & MN_ITF_F_UP) == 0) {
+            continue;
+        }
+        if (itf.mif_flags & MN_ITF_F_MULTICAST) {
+            return itf.mif_idx;
+        }
+    }
+    return -1;
+}
+
+void
+sum4_readable(void *cb_arg, int err)
+{
+    os_sem_release(&test_sem);
+}
+
+static void
+sock_udp_mcast_v4(void)
+{
+    int loop_if_idx;
+    struct mn_socket *rx_sock;
+    struct mn_socket *tx_sock;
+    struct mn_sockaddr_in msin;
+    union mn_socket_cb sock_cbs = {
+        .socket.readable = sum4_readable
+    };
+    struct os_mbuf *m;
+    char data[] = "1234567890";
+    int rc;
+    struct mn_mreq mreq;
+    loop_if_idx = sock_find_multicast_if();
+    TEST_ASSERT(loop_if_idx > 0);
+
+    msin.msin_family = MN_AF_INET;
+    msin.msin_len = sizeof(msin);
+    msin.msin_port = htons(44344);
+    memset(&msin.msin_addr, 0, sizeof(msin.msin_addr));
+
+    rc = mn_socket(&rx_sock, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(rx_sock, NULL, &sock_cbs);
+
+    rc = mn_bind(rx_sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_socket(&tx_sock, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_setsockopt(tx_sock, MN_SO_LEVEL, MN_MCAST_IF, &loop_if_idx);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * multicast tgt
+     */
+    mn_inet_pton(MN_PF_INET, "224.0.2.241", &msin.msin_addr);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * RX socket has not joined group yet.
+     */
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC / 2);
+    TEST_ASSERT(rc == OS_TIMEOUT);
+
+    mreq.mm_idx = loop_if_idx;
+    mreq.mm_family = MN_AF_INET;
+    mreq.mm_addr.v4.s_addr = msin.msin_addr.s_addr;
+
+    /*
+     * Now join it.
+     */
+    rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_JOIN_GROUP, &mreq);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_recvfrom(rx_sock, &m, NULL);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+    TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data)));
+    os_mbuf_free_chain(m);
+
+    /*
+     * Then leave
+     */
+    rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_LEAVE_GROUP, &mreq);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    TEST_ASSERT(m);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == OS_TIMEOUT);
+
+    mn_close(rx_sock);
+    mn_close(tx_sock);
+}
+
+static void
+sock_udp_mcast_v6(void)
+{
+    int loop_if_idx;
+    struct mn_socket *rx_sock;
+    struct mn_socket *tx_sock;
+    struct mn_sockaddr_in6 msin6;
+    union mn_socket_cb sock_cbs = {
+        .socket.readable = sum4_readable
+    };
+    struct os_mbuf *m;
+    char data[] = "1234567890";
+    int rc;
+    struct mn_mreq mreq;
+    uint8_t mcast_addr[16] = {
+        0xff, 2, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 2
+    };
+
+    loop_if_idx = sock_find_multicast_if();
+    TEST_ASSERT(loop_if_idx > 0);
+
+    msin6.msin6_family = MN_AF_INET6;
+    msin6.msin6_len = sizeof(msin6);
+    msin6.msin6_port = htons(44344);
+    memset(&msin6.msin6_addr, 0, sizeof(msin6.msin6_addr));
+
+    rc = mn_socket(&rx_sock, MN_PF_INET6, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(rx_sock, NULL, &sock_cbs);
+
+    rc = mn_bind(rx_sock, (struct mn_sockaddr *)&msin6);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_socket(&tx_sock, MN_PF_INET6, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_setsockopt(tx_sock, MN_SO_LEVEL, MN_MCAST_IF, &loop_if_idx);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * multicast tgt
+     */
+    memcpy(&msin6.msin6_addr, mcast_addr, sizeof(mcast_addr));
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin6);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * RX socket has not joined group yet.
+     */
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC / 2);
+    TEST_ASSERT(rc == OS_TIMEOUT);
+
+    mreq.mm_idx = loop_if_idx;
+    mreq.mm_family = MN_AF_INET6;
+    memcpy(&mreq.mm_addr.v6.s_addr, msin6.msin6_addr.s_addr,
+      sizeof(msin6.msin6_addr.s_addr));
+
+    /*
+     * Now join it.
+     */
+    rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_JOIN_GROUP, &mreq);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin6);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_recvfrom(rx_sock, &m, NULL);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+    TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data)));
+    os_mbuf_free_chain(m);
+
+    /*
+     * Then leave
+     */
+    rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_LEAVE_GROUP, &mreq);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    TEST_ASSERT(m);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin6);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == OS_TIMEOUT);
+
+    mn_close(rx_sock);
+    mn_close(tx_sock);
+}
+
+void
+mn_socket_test_handler(void *arg)
+{
+    sock_open_close();
+    sock_listen();
+    sock_tcp_connect();
+    sock_udp_data();
+    sock_tcp_data();
+    sock_itf_list();
+    sock_udp_ll();
+    sock_udp_mcast_v4();
+    sock_udp_mcast_v6();
+    tu_restart();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/net/ip/mn_socket/test/src/testcases/inet_ntop_test.c
----------------------------------------------------------------------
diff --git a/net/ip/mn_socket/test/src/testcases/inet_ntop_test.c 
b/net/ip/mn_socket/test/src/testcases/inet_ntop_test.c
new file mode 100644
index 0000000..7ef13d5
--- /dev/null
+++ b/net/ip/mn_socket/test/src/testcases/inet_ntop_test.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 "mn_sock_test.h"
+
+TEST_CASE(inet_ntop_test)
+{
+    const char *rstr;
+    char addr[48];
+    struct test_vec {
+        char *str;
+        uint8_t cmp[4];
+    };
+    struct test_vec ok_vec[] = {
+        { "1.1.1.1", { 1, 1, 1, 1 } },
+        { "1.2.3.4", { 1, 2, 3, 4 } },
+        { "255.1.255.255", { 255, 1, 255, 255 } },
+        { "1.2.5.6", { 1, 2, 5, 6 } }
+    };
+    int i;
+
+    for (i = 0; i < sizeof(ok_vec) / sizeof(ok_vec[0]); i++) {
+        memset(addr, 0xa5, sizeof(addr));
+        rstr = mn_inet_ntop(MN_PF_INET, ok_vec[i].cmp, addr, sizeof(addr));
+        TEST_ASSERT(rstr);
+        TEST_ASSERT(!strcmp(ok_vec[i].str, addr));
+    }
+    rstr = mn_inet_ntop(MN_PF_INET, ok_vec[0].cmp, addr, 1);
+    TEST_ASSERT(rstr == NULL);
+
+    /* does not have space to null terminate */
+    rstr = mn_inet_ntop(MN_PF_INET, ok_vec[0].cmp, addr, 7);
+    TEST_ASSERT(rstr == NULL);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/net/ip/mn_socket/test/src/testcases/inet_pton_test.c
----------------------------------------------------------------------
diff --git a/net/ip/mn_socket/test/src/testcases/inet_pton_test.c 
b/net/ip/mn_socket/test/src/testcases/inet_pton_test.c
new file mode 100644
index 0000000..f1413d6
--- /dev/null
+++ b/net/ip/mn_socket/test/src/testcases/inet_pton_test.c
@@ -0,0 +1,55 @@
+/**
+ * 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 "mn_sock_test.h"
+
+TEST_CASE(inet_pton_test)
+{
+    int rc;
+    uint8_t addr[8];
+    struct test_vec {
+        char *str;
+        uint8_t cmp[4];
+    };
+    struct test_vec ok_vec[] = {
+        { "1.1.1.1", { 1, 1, 1, 1 } },
+        { "1.2.3.4", { 1, 2, 3, 4 } },
+        { "010.001.255.255", { 10, 1, 255, 255 } },
+        { "001.002.005.006", { 1, 2, 5, 6 } }
+    };
+    struct test_vec invalid_vec[] = {
+        { "a.b.c.d" },
+        { "1a.b3.4.2" },
+        { "1.3.4.2a" },
+        { "1111.3.4.2" },
+        { "3.256.1.0" },
+    };
+    int i;
+
+    for (i = 0; i < sizeof(ok_vec) / sizeof(ok_vec[0]); i++) {
+        memset(addr, 0xa5, sizeof(addr));
+        rc = mn_inet_pton(MN_PF_INET, ok_vec[i].str, addr);
+        TEST_ASSERT(rc == 1);
+        TEST_ASSERT(!memcmp(ok_vec[i].cmp, addr, sizeof(uint32_t)));
+        TEST_ASSERT(addr[5] == 0xa5);
+    }
+    for (i = 0; i < sizeof(invalid_vec) / sizeof(invalid_vec[0]); i++) {
+        rc = mn_inet_pton(MN_PF_INET, invalid_vec[i].str, addr);
+        TEST_ASSERT(rc == 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/net/ip/mn_socket/test/src/testcases/socket_tests.c
----------------------------------------------------------------------
diff --git a/net/ip/mn_socket/test/src/testcases/socket_tests.c 
b/net/ip/mn_socket/test/src/testcases/socket_tests.c
new file mode 100644
index 0000000..5bbc0f7
--- /dev/null
+++ b/net/ip/mn_socket/test/src/testcases/socket_tests.c
@@ -0,0 +1,31 @@
+/**
+ * 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 "mn_sock_test.h"
+
+TEST_CASE(socket_tests)
+{
+    sysinit();
+    native_sock_init();
+
+    os_sem_init(&test_sem, 0);
+
+    os_task_init(&test_task, "mn_socket_test", mn_socket_test_handler, NULL,
+      TEST_PRIO, OS_WAIT_FOREVER, test_stack, TEST_STACK_SIZE);
+    os_start();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/net/nimble/host/test/src/ble_hs_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_hs_test.c 
b/net/nimble/host/test/src/ble_hs_test.c
index e1f4dad..2b0239c 100644
--- a/net/nimble/host/test/src/ble_hs_test.c
+++ b/net/nimble/host/test/src/ble_hs_test.c
@@ -29,7 +29,7 @@
 int
 main(int argc, char **argv)
 {
-    tu_config.tc_print_results = 1;
+    ts_config.ts_print_results = 1;
     tu_parse_args(argc, argv);
 
     tu_init();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/include/config/config_fcb.h
----------------------------------------------------------------------
diff --git a/sys/config/include/config/config_fcb.h 
b/sys/config/include/config/config_fcb.h
index b2ed7a2..807af24 100644
--- a/sys/config/include/config/config_fcb.h
+++ b/sys/config/include/config/config_fcb.h
@@ -30,8 +30,8 @@ struct conf_fcb {
     struct fcb cf_fcb;
 };
 
-int conf_fcb_src(struct conf_fcb *fcb);
-int conf_fcb_dst(struct conf_fcb *fcb);
+extern int conf_fcb_src(struct conf_fcb *cf);
+extern int conf_fcb_dst(struct conf_fcb *cf);
 
 #ifdef __cplusplus
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/pkg.yml
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/pkg.yml b/sys/config/test-fcb/pkg.yml
new file mode 100644
index 0000000..c5cd984
--- /dev/null
+++ b/sys/config/test-fcb/pkg.yml
@@ -0,0 +1,31 @@
+# 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: sys/config/test-fcb
+pkg.type: unittest
+pkg.description: "Config unit tests for fcb."
+pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+
+pkg.deps: 
+    - test/testutil
+    - sys/config
+
+pkg.deps.SELFTEST:
+    - fs/fcb
+    - sys/console/stub

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/conf_test_fcb.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/conf_test_fcb.c 
b/sys/config/test-fcb/src/conf_test_fcb.c
new file mode 100644
index 0000000..f2cae7d
--- /dev/null
+++ b/sys/config/test-fcb/src/conf_test_fcb.c
@@ -0,0 +1,363 @@
+/**
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <os/os.h>
+#include <flash_map/flash_map.h>
+#include <testutil/testutil.h>
+#include <fcb/fcb.h>
+#include "config/config.h"
+#include "config/config_file.h"
+#include "config/config_fcb.h"
+#include "config_priv.h"
+#include "conf_test_fcb.h"
+
+uint8_t val8;
+int c2_var_count = 1;
+
+char val_string[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+
+uint32_t val32;
+
+int test_get_called;
+int test_set_called;
+int test_commit_called;
+int test_export_block;
+
+char *ctest_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int ctest_handle_set(int argc, char **argv, char *val);
+int ctest_handle_commit(void);
+int ctest_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+char *c2_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int c2_handle_set(int argc, char **argv, char *val);
+int c2_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+char *c3_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int c3_handle_set(int argc, char **argv, char *val);
+int c3_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+
+struct conf_handler config_test_handler = {
+    .ch_name = "myfoo",
+    .ch_get = ctest_handle_get,
+    .ch_set = ctest_handle_set,
+    .ch_commit = ctest_handle_commit,
+    .ch_export = ctest_handle_export
+};
+
+char *
+ctest_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    test_get_called = 1;
+    if (argc == 1 && !strcmp(argv[0], "mybar")) {
+        return conf_str_from_value(CONF_INT8, &val8, val, val_len_max);
+    }
+    return NULL;
+}
+
+int
+ctest_handle_set(int argc, char **argv, char *val)
+{
+    uint8_t newval;
+    int rc;
+
+    test_set_called = 1;
+    if (argc == 1 && !strcmp(argv[0], "mybar")) {
+        rc = CONF_VALUE_SET(val, CONF_INT8, newval);
+        TEST_ASSERT(rc == 0);
+        val8 = newval;
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+ctest_handle_commit(void)
+{
+    test_commit_called = 1;
+    return 0;
+}
+
+int
+ctest_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    char value[32];
+
+    if (test_export_block) {
+        return 0;
+    }
+    conf_str_from_value(CONF_INT8, &val8, value, sizeof(value));
+    cb("myfoo/mybar", value);
+
+    return 0;
+}
+
+struct conf_handler c2_test_handler = {
+    .ch_name = "2nd",
+    .ch_get = c2_handle_get,
+    .ch_set = c2_handle_set,
+    .ch_commit = NULL,
+    .ch_export = c2_handle_export
+};
+
+char *
+c2_var_find(char *name)
+{
+    int idx = 0;
+    int len;
+    char *eptr;
+
+    len = strlen(name);
+    TEST_ASSERT(!strncmp(name, "string", 6));
+    TEST_ASSERT(len > 6);
+
+    idx = strtoul(&name[6], &eptr, 10);
+    TEST_ASSERT(*eptr == '\0');
+    TEST_ASSERT(idx < c2_var_count);
+    return val_string[idx];
+}
+
+char *
+c2_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    int len;
+    char *valptr;
+
+    if (argc == 1) {
+        valptr = c2_var_find(argv[0]);
+        if (!valptr) {
+            return NULL;
+        }
+        len = strlen(val_string[0]);
+        if (len > val_len_max) {
+            len = val_len_max;
+        }
+        strncpy(val, valptr, len);
+    }
+    return NULL;
+}
+
+int
+c2_handle_set(int argc, char **argv, char *val)
+{
+    char *valptr;
+
+    if (argc == 1) {
+        valptr = c2_var_find(argv[0]);
+        if (!valptr) {
+            return OS_ENOENT;
+        }
+        if (val) {
+            strncpy(valptr, val, sizeof(val_string[0]));
+        } else {
+            memset(valptr, 0, sizeof(val_string[0]));
+        }
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+c2_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    int i;
+    char name[32];
+
+    for (i = 0; i < c2_var_count; i++) {
+        snprintf(name, sizeof(name), "2nd/string%d", i);
+        cb(name, val_string[i]);
+    }
+    return 0;
+}
+
+struct conf_handler c3_test_handler = {
+    .ch_name = "3",
+    .ch_get = c3_handle_get,
+    .ch_set = c3_handle_set,
+    .ch_commit = NULL,
+    .ch_export = c3_handle_export
+};
+
+char *
+c3_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    if (argc == 1 && !strcmp(argv[0], "v")) {
+        return conf_str_from_value(CONF_INT32, &val32, val, val_len_max);
+    }
+    return NULL;
+}
+
+int
+c3_handle_set(int argc, char **argv, char *val)
+{
+    uint32_t newval;
+    int rc;
+
+    if (argc == 1 && !strcmp(argv[0], "v")) {
+        rc = CONF_VALUE_SET(val, CONF_INT32, newval);
+        TEST_ASSERT(rc == 0);
+        val32 = newval;
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+c3_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    char value[32];
+
+    conf_str_from_value(CONF_INT32, &val32, value, sizeof(value));
+    cb("3/v", value);
+
+    return 0;
+}
+
+void
+ctest_clear_call_state(void)
+{
+    test_get_called = 0;
+    test_set_called = 0;
+    test_commit_called = 0;
+}
+
+int
+ctest_get_call_state(void)
+{
+    return test_get_called + test_set_called + test_commit_called;
+}
+
+void config_wipe_srcs(void)
+{
+    SLIST_INIT(&conf_load_srcs);
+    conf_save_dst = NULL;
+}
+
+void config_wipe_fcb(struct flash_area *fa, int cnt)
+{
+    int i;
+
+    for (i = 0; i < cnt; i++) {
+        flash_area_erase(&fa[i], 0, fa[i].fa_size);
+    }
+}
+
+struct flash_area fcb_areas[] = {
+    [0] = {
+        .fa_off = 0x00000000,
+        .fa_size = 16 * 1024
+    },
+    [1] = {
+        .fa_off = 0x00004000,
+        .fa_size = 16 * 1024
+    },
+    [2] = {
+        .fa_off = 0x00008000,
+        .fa_size = 16 * 1024
+    },
+    [3] = {
+        .fa_off = 0x0000c000,
+        .fa_size = 16 * 1024
+    }
+};
+
+void
+config_test_fill_area(
+          char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN],
+          int iteration)
+{
+      int i, j;
+
+      for (j = 0; j < 64; j++) {
+          for (i = 0; i < CONF_MAX_VAL_LEN; i++) {
+              test_value[j][i] = ((j * 2) + i + iteration) % 10 + '0';
+          }
+          test_value[j][sizeof(test_value[j]) - 1] = '\0';
+      }
+}
+
+TEST_CASE_DECL(config_empty_lookups)
+TEST_CASE_DECL(config_test_insert)
+TEST_CASE_DECL(config_test_getset_unknown)
+TEST_CASE_DECL(config_test_getset_int)
+TEST_CASE_DECL(config_test_getset_bytes)
+TEST_CASE_DECL(config_test_commit)
+TEST_CASE_DECL(config_test_empty_fcb)
+TEST_CASE_DECL(config_test_save_1_fcb)
+TEST_CASE_DECL(config_test_insert2)
+TEST_CASE_DECL(config_test_save_2_fcb)
+TEST_CASE_DECL(config_test_insert3)
+TEST_CASE_DECL(config_test_save_3_fcb)
+TEST_CASE_DECL(config_test_compress_reset)
+TEST_CASE_DECL(config_test_save_one_fcb)
+
+TEST_SUITE(config_test_all)
+{
+    /*
+     * Config tests.
+     */
+    config_empty_lookups();
+    config_test_insert();
+    config_test_getset_unknown();
+    config_test_getset_int();
+    config_test_getset_bytes();
+
+    config_test_commit();
+
+    /*
+     * FCB as backing storage.
+     */
+    config_test_empty_fcb();
+    config_test_save_1_fcb();
+
+    config_test_insert2();
+
+    config_test_save_2_fcb();
+
+    config_test_insert3();
+    config_test_save_3_fcb();
+
+    config_test_compress_reset();
+
+    config_test_save_one_fcb();
+}
+
+#if MYNEWT_VAL(SELFTEST)
+
+int
+main(int argc, char **argv)
+{
+    ts_config.ts_print_results = 1;
+    tu_init();
+
+    conf_init();
+    config_test_all();
+
+    return tu_any_failed;
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/conf_test_fcb.h
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/conf_test_fcb.h 
b/sys/config/test-fcb/src/conf_test_fcb.h
new file mode 100644
index 0000000..618ae19
--- /dev/null
+++ b/sys/config/test-fcb/src/conf_test_fcb.h
@@ -0,0 +1,90 @@
+/**
+ * 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 _CONF_TEST_FCB_H
+#define _CONF_TEST_FCB_H
+
+#include <stdio.h>
+#include <string.h>
+#include <syscfg/syscfg.h>
+#include <os/os.h>
+#include <flash_map/flash_map.h>
+#include <testutil/testutil.h>
+#include <fcb/fcb.h>
+#include <config/config.h>
+#include <config/config_fcb.h>
+#include "config_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint8_t val8;
+int c2_var_count;
+
+#define CONF_TEST_FCB_VAL_STR_CNT   64
+
+extern char val_string[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+
+#define CONF_TEST_FCB_FLASH_CNT   4
+
+extern struct flash_area fcb_areas[CONF_TEST_FCB_FLASH_CNT];
+
+uint32_t val32;
+
+int test_get_called;
+int test_set_called;
+int test_commit_called;
+int test_export_block;
+
+void ctest_clear_call_state(void);
+int ctest_get_call_state(void);
+void config_wipe_srcs(void);
+extern void config_test_fill_area(
+        char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN],
+        int iteration);
+
+void config_wipe_fcb(struct flash_area *fa, int cnt);
+
+char *ctest_handle_get(int argc, char **argv, char *val, int val_len_max);
+int ctest_handle_set(int argc, char **argv, char *val);
+int ctest_handle_commit(void);
+int ctest_handle_export(void (*cb)(char *name, char *value),
+                        enum conf_export_tgt tgt);
+
+char *c2_handle_get(int argc, char **argv, char *val, int val_len_max);
+int c2_handle_set(int argc, char **argv, char *val);
+int c2_handle_export(void (*cb)(char *name, char *value),
+                     enum conf_export_tgt tgt);
+
+char *c3_handle_get(int argc, char **argv, char *val, int val_len_max);
+int c3_handle_set(int argc, char **argv, char *val);
+int c3_handle_export(void (*cb)(char *name, char *value),
+                     enum conf_export_tgt tgt);
+
+struct conf_handler config_test_handler;
+
+struct conf_handler c2_test_handler;
+
+struct conf_handler c3_test_handler;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONF_TEST_FCB_H */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_empty_lookups.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_empty_lookups.c 
b/sys/config/test-fcb/src/testcases/config_empty_lookups.c
new file mode 100644
index 0000000..768f083
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_empty_lookups.c
@@ -0,0 +1,34 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_empty_lookups)
+{
+    int rc;
+    char name[80];
+    char tmp[64], *str;
+
+    strcpy(name, "foo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc != 0);
+
+    strcpy(name, "foo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_commit.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_commit.c 
b/sys/config/test-fcb/src/testcases/config_test_commit.c
new file mode 100644
index 0000000..4078bff
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_commit.c
@@ -0,0 +1,41 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_commit)
+{
+    char name[80];
+    int rc;
+
+    strcpy(name, "bar");
+    rc = conf_commit(name);
+    TEST_ASSERT(rc);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    rc = conf_commit(NULL);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_commit_called == 1);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo");
+    rc = conf_commit(name);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_commit_called == 1);
+    ctest_clear_call_state();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_compress_reset.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_compress_reset.c 
b/sys/config/test-fcb/src/testcases/config_test_compress_reset.c
new file mode 100644
index 0000000..2d16e6a
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_compress_reset.c
@@ -0,0 +1,88 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_compress_reset)
+{
+    int rc;
+    struct conf_fcb cf;
+    struct flash_area *fa;
+    char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+    int elems[4];
+    int i;
+
+    config_wipe_srcs();
+    config_wipe_fcb(fcb_areas, sizeof(fcb_areas) / sizeof(fcb_areas[0]));
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = sizeof(fcb_areas) / sizeof(fcb_areas[0]);
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    c2_var_count = 1;
+    memset(elems, 0, sizeof(elems));
+
+    for (i = 0; ; i++) {
+        config_test_fill_area(test_value, i);
+        memcpy(val_string, test_value, sizeof(val_string));
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        if (cf.cf_fcb.f_active.fe_area == &fcb_areas[2]) {
+            /*
+             * Started using space just before scratch.
+             */
+            break;
+        }
+        memset(val_string, 0, sizeof(val_string));
+
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(!memcmp(val_string, test_value, CONF_MAX_VAL_LEN));
+    }
+
+    fa = cf.cf_fcb.f_active.fe_area;
+    rc = fcb_append_to_scratch(&cf.cf_fcb);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(fcb_free_sector_cnt(&cf.cf_fcb) == 0);
+    TEST_ASSERT(fa != cf.cf_fcb.f_active.fe_area);
+
+    config_wipe_srcs();
+
+    memset(&cf, 0, sizeof(cf));
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = sizeof(fcb_areas) / sizeof(fcb_areas[0]);
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    TEST_ASSERT(fcb_free_sector_cnt(&cf.cf_fcb) == 1);
+    TEST_ASSERT(fa == cf.cf_fcb.f_active.fe_area);
+
+    c2_var_count = 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_empty_fcb.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_empty_fcb.c 
b/sys/config/test-fcb/src/testcases/config_test_empty_fcb.c
new file mode 100644
index 0000000..5c62e47
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_empty_fcb.c
@@ -0,0 +1,42 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_empty_fcb)
+{
+    int rc;
+    struct conf_fcb cf;
+
+    config_wipe_srcs();
+    config_wipe_fcb(fcb_areas, sizeof(fcb_areas) / sizeof(fcb_areas[0]));
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = sizeof(fcb_areas) / sizeof(fcb_areas[0]);
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * No values
+     */
+    conf_load();
+
+    config_wipe_srcs();
+    ctest_clear_call_state();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_getset_bytes.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_getset_bytes.c 
b/sys/config/test-fcb/src/testcases/config_test_getset_bytes.c
new file mode 100644
index 0000000..f545794
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_getset_bytes.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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_getset_bytes)
+{
+    char orig[32];
+    char bytes[32];
+    char str[48];
+    char *ret;
+    int j, i;
+    int tmp;
+    int rc;
+
+    for (j = 1; j < sizeof(orig); j++) {
+        for (i = 0; i < j; i++) {
+            orig[i] = i + j + 1;
+        }
+        ret = conf_str_from_bytes(orig, j, str, sizeof(str));
+        TEST_ASSERT(ret);
+        tmp = strlen(str);
+        TEST_ASSERT(tmp < sizeof(str));
+
+        memset(bytes, 0, sizeof(bytes));
+        tmp = sizeof(bytes);
+
+        tmp = sizeof(bytes);
+        rc = conf_bytes_from_str(str, bytes, &tmp);
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(tmp == j);
+        TEST_ASSERT(!memcmp(orig, bytes, j));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_getset_int.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_getset_int.c 
b/sys/config/test-fcb/src/testcases/config_test_getset_int.c
new file mode 100644
index 0000000..fbf841e
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_getset_int.c
@@ -0,0 +1,40 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_getset_int)
+{
+    char name[80];
+    char tmp[64], *str;
+    int rc;
+
+    strcpy(name, "myfoo/mybar");
+    rc = conf_set_value(name, "42");
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_set_called == 1);
+    TEST_ASSERT(val8 == 42);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/mybar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str);
+    TEST_ASSERT(test_get_called == 1);
+    TEST_ASSERT(!strcmp("42", tmp));
+    ctest_clear_call_state();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_getset_unknown.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_getset_unknown.c 
b/sys/config/test-fcb/src/testcases/config_test_getset_unknown.c
new file mode 100644
index 0000000..60e1309
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_getset_unknown.c
@@ -0,0 +1,48 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_getset_unknown)
+{
+    char name[80];
+    char tmp[64], *str;
+    int rc;
+
+    strcpy(name, "foo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc != 0);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    strcpy(name, "foo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    strcpy(name, "myfoo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc == OS_ENOENT);
+    TEST_ASSERT(test_set_called == 1);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+    TEST_ASSERT(test_get_called == 1);
+    ctest_clear_call_state();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_insert.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_insert.c 
b/sys/config/test-fcb/src/testcases/config_test_insert.c
new file mode 100644
index 0000000..7ff5ef3
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_insert.c
@@ -0,0 +1,27 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_insert)
+{
+    int rc;
+
+    rc = conf_register(&config_test_handler);
+    TEST_ASSERT(rc == 0);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_insert2.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_insert2.c 
b/sys/config/test-fcb/src/testcases/config_test_insert2.c
new file mode 100644
index 0000000..a667447
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_insert2.c
@@ -0,0 +1,27 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_insert2)
+{
+    int rc;
+
+    rc = conf_register(&c2_test_handler);
+    TEST_ASSERT(rc == 0);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_insert3.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_insert3.c 
b/sys/config/test-fcb/src/testcases/config_test_insert3.c
new file mode 100644
index 0000000..db72c46
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_insert3.c
@@ -0,0 +1,27 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_insert3)
+{
+    int rc;
+
+    rc = conf_register(&c3_test_handler);
+    TEST_ASSERT(rc == 0);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_save_1_fcb.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_save_1_fcb.c 
b/sys/config/test-fcb/src/testcases/config_test_save_1_fcb.c
new file mode 100644
index 0000000..4579b8a
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_save_1_fcb.c
@@ -0,0 +1,46 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_save_1_fcb)
+{
+    int rc;
+    struct conf_fcb cf;
+
+    config_wipe_srcs();
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = sizeof(fcb_areas) / sizeof(fcb_areas[0]);
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    val8 = 33;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    val8 = 0;
+
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 33);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_save_2_fcb.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_save_2_fcb.c 
b/sys/config/test-fcb/src/testcases/config_test_save_2_fcb.c
new file mode 100644
index 0000000..4cf4b1a
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_save_2_fcb.c
@@ -0,0 +1,76 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_save_2_fcb)
+{
+    int rc;
+    struct conf_fcb cf;
+    char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+    int i;
+
+    config_wipe_srcs();
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = sizeof(fcb_areas) / sizeof(fcb_areas[0]);
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    config_test_fill_area(test_value, 0);
+    memcpy(val_string, test_value, sizeof(val_string));
+
+    val8 = 42;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    val8 = 0;
+    memset(val_string[0], 0, sizeof(val_string[0]));
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 42);
+    TEST_ASSERT(!strcmp(val_string[0], test_value[0]));
+    test_export_block = 1;
+
+    /*
+     * Now add the number of settings to max. Keep adjusting the test_data,
+     * check that rollover happens when it's supposed to.
+     */
+    c2_var_count = 64;
+
+    for (i = 0; i < 32; i++) {
+        config_test_fill_area(test_value, i);
+        memcpy(val_string, test_value, sizeof(val_string));
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        memset(val_string, 0, sizeof(val_string));
+
+        val8 = 0;
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(!memcmp(val_string, test_value, sizeof(val_string)));
+        TEST_ASSERT(val8 == 42);
+    }
+    c2_var_count = 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_save_3_fcb.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_save_3_fcb.c 
b/sys/config/test-fcb/src/testcases/config_test_save_3_fcb.c
new file mode 100644
index 0000000..69de5f1
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_save_3_fcb.c
@@ -0,0 +1,51 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_save_3_fcb)
+{
+    int rc;
+    struct conf_fcb cf;
+    int i;
+
+    config_wipe_srcs();
+    config_wipe_fcb(fcb_areas, sizeof(fcb_areas) / sizeof(fcb_areas[0]));
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = 4;
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    for (i = 0; i < 4096; i++) {
+        val32 = i;
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        val32 = 0;
+
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(val32 == i);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/src/testcases/config_test_save_one_fcb.c
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/src/testcases/config_test_save_one_fcb.c 
b/sys/config/test-fcb/src/testcases/config_test_save_one_fcb.c
new file mode 100644
index 0000000..25932fa
--- /dev/null
+++ b/sys/config/test-fcb/src/testcases/config_test_save_one_fcb.c
@@ -0,0 +1,55 @@
+/**
+ * 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 "conf_test_fcb.h"
+
+TEST_CASE(config_test_save_one_fcb)
+{
+    int rc;
+    struct conf_fcb cf;
+
+    config_wipe_srcs();
+    config_wipe_fcb(fcb_areas, sizeof(fcb_areas) / sizeof(fcb_areas[0]));
+
+    cf.cf_fcb.f_sectors = fcb_areas;
+    cf.cf_fcb.f_sector_cnt = sizeof(fcb_areas) / sizeof(fcb_areas[0]);
+
+    rc = conf_fcb_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    val8 = 33;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_save_one("myfoo/mybar", "42");
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 42);
+
+    rc = conf_save_one("myfoo/mybar", "44");
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 44);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-fcb/syscfg.yml
----------------------------------------------------------------------
diff --git a/sys/config/test-fcb/syscfg.yml b/sys/config/test-fcb/syscfg.yml
new file mode 100644
index 0000000..bb352e4
--- /dev/null
+++ b/sys/config/test-fcb/syscfg.yml
@@ -0,0 +1,4 @@
+# Package: sys/config/test-fcb
+
+syscfg.vals:
+    CONFIG_FCB: 1

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-nffs/pkg.yml
----------------------------------------------------------------------
diff --git a/sys/config/test-nffs/pkg.yml b/sys/config/test-nffs/pkg.yml
new file mode 100644
index 0000000..87f6161
--- /dev/null
+++ b/sys/config/test-nffs/pkg.yml
@@ -0,0 +1,31 @@
+# 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: sys/config/test-nffs
+pkg.type: unittest
+pkg.description: "Config unit tests for nffs."
+pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+
+pkg.deps: 
+    - test/testutil
+    - sys/config
+
+pkg.deps.SELFTEST:
+    - fs/nffs
+    - sys/console/stub

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-nffs/src/conf_test_nffs.c
----------------------------------------------------------------------
diff --git a/sys/config/test-nffs/src/conf_test_nffs.c 
b/sys/config/test-nffs/src/conf_test_nffs.c
new file mode 100644
index 0000000..bd4706f
--- /dev/null
+++ b/sys/config/test-nffs/src/conf_test_nffs.c
@@ -0,0 +1,367 @@
+/**
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <os/os.h>
+#include <testutil/testutil.h>
+#include <nffs/nffs.h>
+#include <fs/fs.h>
+#include <fs/fsutil.h>
+#include "config/config.h"
+#include "config/config_file.h"
+#include "config_priv.h"
+
+uint8_t val8;
+int c2_var_count = 1;
+char val_string[64][CONF_MAX_VAL_LEN];
+
+uint32_t val32;
+
+int test_get_called;
+int test_set_called;
+int test_commit_called;
+int test_export_block;
+
+char *ctest_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int ctest_handle_set(int argc, char **argv, char *val);
+int ctest_handle_commit(void);
+int ctest_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+char *c2_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int c2_handle_set(int argc, char **argv, char *val);
+int c2_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+char *c3_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int c3_handle_set(int argc, char **argv, char *val);
+int c3_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+
+struct conf_handler config_test_handler = {
+    .ch_name = "myfoo",
+    .ch_get = ctest_handle_get,
+    .ch_set = ctest_handle_set,
+    .ch_commit = ctest_handle_commit,
+    .ch_export = ctest_handle_export
+};
+
+char *
+ctest_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    test_get_called = 1;
+    if (argc == 1 && !strcmp(argv[0], "mybar")) {
+        return conf_str_from_value(CONF_INT8, &val8, val, val_len_max);
+    }
+    return NULL;
+}
+
+int
+ctest_handle_set(int argc, char **argv, char *val)
+{
+    uint8_t newval;
+    int rc;
+
+    test_set_called = 1;
+    if (argc == 1 && !strcmp(argv[0], "mybar")) {
+        rc = CONF_VALUE_SET(val, CONF_INT8, newval);
+        TEST_ASSERT(rc == 0);
+        val8 = newval;
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+ctest_handle_commit(void)
+{
+    test_commit_called = 1;
+    return 0;
+}
+
+int
+ctest_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    char value[32];
+
+    if (test_export_block) {
+        return 0;
+    }
+    conf_str_from_value(CONF_INT8, &val8, value, sizeof(value));
+    cb("myfoo/mybar", value);
+
+    return 0;
+}
+
+struct conf_handler c2_test_handler = {
+    .ch_name = "2nd",
+    .ch_get = c2_handle_get,
+    .ch_set = c2_handle_set,
+    .ch_commit = NULL,
+    .ch_export = c2_handle_export
+};
+
+char *
+c2_var_find(char *name)
+{
+    int idx = 0;
+    int len;
+    char *eptr;
+
+    len = strlen(name);
+    TEST_ASSERT(!strncmp(name, "string", 6));
+    TEST_ASSERT(len > 6);
+
+    idx = strtoul(&name[6], &eptr, 10);
+    TEST_ASSERT(*eptr == '\0');
+    TEST_ASSERT(idx < c2_var_count);
+    return val_string[idx];
+}
+
+char *
+c2_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    int len;
+    char *valptr;
+
+    if (argc == 1) {
+        valptr = c2_var_find(argv[0]);
+        if (!valptr) {
+            return NULL;
+        }
+        len = strlen(val_string[0]);
+        if (len > val_len_max) {
+            len = val_len_max;
+        }
+        strncpy(val, valptr, len);
+    }
+    return NULL;
+}
+
+int
+c2_handle_set(int argc, char **argv, char *val)
+{
+    char *valptr;
+
+    if (argc == 1) {
+        valptr = c2_var_find(argv[0]);
+        if (!valptr) {
+            return OS_ENOENT;
+        }
+        if (val) {
+            strncpy(valptr, val, sizeof(val_string[0]));
+        } else {
+            memset(valptr, 0, sizeof(val_string[0]));
+        }
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+c2_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    int i;
+    char name[32];
+
+    for (i = 0; i < c2_var_count; i++) {
+        snprintf(name, sizeof(name), "2nd/string%d", i);
+        cb(name, val_string[i]);
+    }
+    return 0;
+}
+
+struct conf_handler c3_test_handler = {
+    .ch_name = "3",
+    .ch_get = c3_handle_get,
+    .ch_set = c3_handle_set,
+    .ch_commit = NULL,
+    .ch_export = c3_handle_export
+};
+
+char *
+c3_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    if (argc == 1 && !strcmp(argv[0], "v")) {
+        return conf_str_from_value(CONF_INT32, &val32, val, val_len_max);
+    }
+    return NULL;
+}
+
+int
+c3_handle_set(int argc, char **argv, char *val)
+{
+    uint32_t newval;
+    int rc;
+
+    if (argc == 1 && !strcmp(argv[0], "v")) {
+        rc = CONF_VALUE_SET(val, CONF_INT32, newval);
+        TEST_ASSERT(rc == 0);
+        val32 = newval;
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+c3_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    char value[32];
+
+    conf_str_from_value(CONF_INT32, &val32, value, sizeof(value));
+    cb("3/v", value);
+
+    return 0;
+}
+
+void
+ctest_clear_call_state(void)
+{
+    test_get_called = 0;
+    test_set_called = 0;
+    test_commit_called = 0;
+}
+
+int
+ctest_get_call_state(void)
+{
+    return test_get_called + test_set_called + test_commit_called;
+}
+
+const struct nffs_area_desc config_nffs[] = {
+    { 0x00000000, 16 * 1024 },
+    { 0x00004000, 16 * 1024 },
+    { 0x00008000, 16 * 1024 },
+    { 0x0000c000, 16 * 1024 },
+    { 0, 0 }
+};
+
+void
+config_wipe_srcs(void)
+{
+    SLIST_INIT(&conf_load_srcs);
+    conf_save_dst = NULL;
+}
+
+int
+conf_test_file_strstr(const char *fname, char *string)
+{
+    int rc;
+    uint32_t len;
+    uint32_t rlen;
+    char *buf;
+    struct fs_file *file;
+
+    rc = fs_open(fname, FS_ACCESS_READ, &file);
+    if (rc) {
+        return rc;
+    }
+    rc = fs_filelen(file, &len);
+    fs_close(file);
+    if (rc) {
+        return rc;
+    }
+
+    buf = (char *)malloc(len + 1);
+    TEST_ASSERT(buf);
+
+    rc = fsutil_read_file(fname, 0, len, buf, &rlen);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(rlen == len);
+    buf[rlen] = '\0';
+
+    if (strstr(buf, string)) {
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+void config_test_fill_area(char test_value[64][CONF_MAX_VAL_LEN],
+  int iteration)
+{
+      int i, j;
+
+      for (j = 0; j < 64; j++) {
+          for (i = 0; i < CONF_MAX_VAL_LEN; i++) {
+              test_value[j][i] = ((j * 2) + i + iteration) % 10 + '0';
+          }
+          test_value[j][sizeof(test_value[j]) - 1] = '\0';
+      }
+}
+
+TEST_CASE_DECL(config_empty_lookups)
+TEST_CASE_DECL(config_test_insert)
+TEST_CASE_DECL(config_test_getset_unknown)
+TEST_CASE_DECL(config_test_getset_int)
+TEST_CASE_DECL(config_test_getset_bytes)
+TEST_CASE_DECL(config_test_commit)
+TEST_CASE_DECL(config_setup_nffs)
+TEST_CASE_DECL(config_test_empty_file)
+TEST_CASE_DECL(config_test_small_file)
+TEST_CASE_DECL(config_test_multiple_in_file)
+TEST_CASE_DECL(config_test_save_in_file)
+TEST_CASE_DECL(config_test_save_one_file)
+
+TEST_SUITE(config_test_all)
+{
+    /*
+     * Config tests.
+     */
+    config_empty_lookups();
+    config_test_insert();
+    config_test_getset_unknown();
+    config_test_getset_int();
+    config_test_getset_bytes();
+
+    config_test_commit();
+
+    /*
+     * NFFS as backing storage.
+     */
+    config_setup_nffs();
+    config_test_empty_file();
+    config_test_small_file();
+    config_test_multiple_in_file();
+
+    config_test_save_in_file();
+
+    config_test_save_one_file();
+}
+
+#if MYNEWT_VAL(SELFTEST)
+
+int
+main(int argc, char **argv)
+{
+    ts_config.ts_print_results = 1;
+    tu_init();
+
+    conf_init();
+    config_test_all();
+
+    return tu_any_failed;
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-nffs/src/conf_test_nffs.h
----------------------------------------------------------------------
diff --git a/sys/config/test-nffs/src/conf_test_nffs.h 
b/sys/config/test-nffs/src/conf_test_nffs.h
new file mode 100644
index 0000000..eb9ee81
--- /dev/null
+++ b/sys/config/test-nffs/src/conf_test_nffs.h
@@ -0,0 +1,87 @@
+/**
+ * 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 _CONF_TEST_H_
+#define _CONF_TEST_H_
+
+#include <stdio.h>
+#include <string.h>
+
+#include "syscfg/syscfg.h"
+
+#include <os/os.h>
+#include <testutil/testutil.h>
+#include <nffs/nffs.h>
+#include <fs/fs.h>
+#include <fs/fsutil.h>
+#include "config/config.h"
+#include "config/config_file.h"
+#include "config_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint8_t val8;
+int c2_var_count;
+char val_string[64][CONF_MAX_VAL_LEN];
+
+uint32_t val32;
+
+int test_get_called;
+int test_set_called;
+int test_commit_called;
+int test_export_block;
+
+char *ctest_handle_get(int argc, char **argv, char *val, int val_len_max);
+int ctest_handle_set(int argc, char **argv, char *val);
+int ctest_handle_commit(void);
+int ctest_handle_export(void (*cb)(char *name, char *value),
+                        enum conf_export_tgt tgt);
+int ctest_get_call_state(void);
+void ctest_clear_call_state(void);
+
+void config_wipe_srcs(void);
+
+int conf_test_file_strstr(const char *fname, char *string);
+
+char *c2_handle_get(int argc, char **argv, char *val, int val_len_max);
+int c2_handle_set(int argc, char **argv, char *val);
+int c2_handle_export(void (*cb)(char *name, char *value),
+                     enum conf_export_tgt tgt);
+
+char *c3_handle_get(int argc, char **argv, char *val, int val_len_max);
+int c3_handle_set(int argc, char **argv, char *val);
+int c3_handle_export(void (*cb)(char *name, char *value),
+                     enum conf_export_tgt tgt);
+
+struct conf_handler config_test_handler;
+
+struct conf_handler c2_test_handler;
+
+struct conf_handler c3_test_handler;
+
+extern struct nffs_area_desc config_nffs[];
+
+void config_test_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONF_TEST_H_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-nffs/src/testcases/config_empty_lookups.c
----------------------------------------------------------------------
diff --git a/sys/config/test-nffs/src/testcases/config_empty_lookups.c 
b/sys/config/test-nffs/src/testcases/config_empty_lookups.c
new file mode 100644
index 0000000..d20a419
--- /dev/null
+++ b/sys/config/test-nffs/src/testcases/config_empty_lookups.c
@@ -0,0 +1,34 @@
+/**
+ * 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 "conf_test_nffs.h"
+
+TEST_CASE(config_empty_lookups)
+{
+    int rc;
+    char name[80];
+    char tmp[64], *str;
+
+    strcpy(name, "foo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc != 0);
+
+    strcpy(name, "foo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-nffs/src/testcases/config_setup_nffs.c
----------------------------------------------------------------------
diff --git a/sys/config/test-nffs/src/testcases/config_setup_nffs.c 
b/sys/config/test-nffs/src/testcases/config_setup_nffs.c
new file mode 100644
index 0000000..5453a4e
--- /dev/null
+++ b/sys/config/test-nffs/src/testcases/config_setup_nffs.c
@@ -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.
+ */
+#include "conf_test_nffs.h"
+
+TEST_CASE(config_setup_nffs)
+{
+    int rc;
+
+    rc = nffs_init();
+    TEST_ASSERT_FATAL(rc == 0);
+    rc = nffs_format(config_nffs);
+    TEST_ASSERT_FATAL(rc == 0);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/75101ba4/sys/config/test-nffs/src/testcases/config_test_commit.c
----------------------------------------------------------------------
diff --git a/sys/config/test-nffs/src/testcases/config_test_commit.c 
b/sys/config/test-nffs/src/testcases/config_test_commit.c
new file mode 100644
index 0000000..03cab12
--- /dev/null
+++ b/sys/config/test-nffs/src/testcases/config_test_commit.c
@@ -0,0 +1,41 @@
+/**
+ * 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 "conf_test_nffs.h"
+
+TEST_CASE(config_test_commit)
+{
+    char name[80];
+    int rc;
+
+    strcpy(name, "bar");
+    rc = conf_commit(name);
+    TEST_ASSERT(rc);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    rc = conf_commit(NULL);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_commit_called == 1);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo");
+    rc = conf_commit(name);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_commit_called == 1);
+    ctest_clear_call_state();
+}


Reply via email to