示例#1
0
static void
test_df1(void **state)
{
    struct state *st = (*state);
    struct lyd_node *node;
    const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\">"
                        "<bar><ho>1</ho><hi>42</hi></bar>"
                        "<foo>42</foo><b1_1>42</b1_1>"
                      "</df><hidden xmlns=\"urn:libyang:tests:defaults\">"
                        "<foo>42</foo><baz>42</baz></hidden>";

    st->dt = lyd_new(NULL, st->mod, "df");
    assert_ptr_not_equal(st->dt, NULL);
    /* presence container */
    assert_ptr_not_equal((node = lyd_new(st->dt, NULL, "bar")), NULL);
    assert_int_not_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0);
    assert_string_equal(ly_errmsg(), "Missing required element \"ho\" in \"bar\".");

    /* manadatory node in bar */
    assert_ptr_not_equal(lyd_new_leaf(node, NULL, "ho", "1"), NULL);
    assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0);

    assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL), 0);

    assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0);
    assert_ptr_not_equal(st->xml, NULL);
    assert_string_equal(st->xml, xml);
}
示例#2
0
static void
test_parse_print_oookeys_xml(void **state)
{
    struct state *st = (*state);
    const char *xmlin = "<cont1 xmlns=\"urn:all\">"
                          "<leaf3>-1</leaf3>"
                          "<list1><leaf18>aaa</leaf18></list1>"
                          "<list1><leaf19>123</leaf19><leaf18>bbb</leaf18></list1>"
                        "</cont1>";
    const char *xmlout = "<cont1 xmlns=\"urn:all\">"
                          "<leaf3>-1</leaf3>"
                          "<list1><leaf18>aaa</leaf18></list1>"
                          "<list1><leaf18>bbb</leaf18><leaf19>123</leaf19></list1>"
                        "</cont1>";
    st->dt = NULL;

    /* with strict parsing, it is error since the key is not encoded as the first child */
    st->dt = lyd_parse_mem(st->ctx, xmlin, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_STRICT);
    assert_ptr_equal(st->dt, NULL);
    assert_int_equal(ly_vecode, LYVE_INORDER);
    assert_string_equal(ly_errmsg(), "Invalid position of the key \"leaf18\" in a list \"list1\".");

    /* without strict, it produces only warning, but the data are correctly loaded */
    st->dt = lyd_parse_mem(st->ctx, xmlin, LYD_XML, LYD_OPT_CONFIG);
    assert_ptr_not_equal(st->dt, NULL);
    assert_int_equal(lyd_print_mem(&st->str1, st->dt, LYD_XML, 0), 0);
    assert_string_equal(st->str1, xmlout);
}
示例#3
0
static void
test_dup_to_ctx(void **state)
{
    struct state *st = (*state);
    const struct lys_module *mod;
    const char *sch = "module x {"
                    "  namespace urn:x;"
                    "  prefix x;"
                    "  leaf x { type string; }}";
    const char *data = "<x xmlns=\"urn:x\">hello</x>";

    /* case 1 - schema is only in the first context, duplicating data into the second context is supposed to
     *          fail because of missing schema */
    mod = lys_parse_mem(st->ctx1, sch, LYS_IN_YANG);
    assert_ptr_not_equal(mod, NULL);

    st->dt1 = lyd_parse_mem(st->ctx1, data, LYD_XML, LYD_OPT_CONFIG);
    assert_ptr_not_equal(st->dt1, NULL);

    st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2);
    assert_ptr_equal(st->dt2, NULL);
    assert_int_equal(ly_errno, LY_EINVAL);
    assert_string_equal(ly_errmsg(st->ctx2),
                        "Target context does not contain schema node for the data node being duplicated (x:x).");

    /* case 2 - with the schema present in both contexts, duplication should succeed */
    mod = lys_parse_mem(st->ctx2, sch, LYS_IN_YANG);
    assert_ptr_not_equal(mod, NULL);

    st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2);
    assert_ptr_not_equal(st->dt2, NULL);
    /* the values are the same, but they are stored in different contexts */
    assert_string_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str,
                        ((struct lyd_node_leaf_list *)st->dt2)->value_str);
    assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str,
                        ((struct lyd_node_leaf_list *)st->dt2)->value_str);
    /* and the schema nodes are the same, but comes from a different contexts */
    assert_int_equal(st->dt1->schema->nodetype, st->dt2->schema->nodetype);
    assert_string_equal(st->dt1->schema->name, st->dt2->schema->name);
    assert_string_equal(st->dt1->schema->module->name, st->dt2->schema->module->name);
    assert_ptr_equal(st->dt1->schema->module->ctx, st->ctx1);
    assert_ptr_equal(st->dt2->schema->module->ctx, st->ctx2);
}
示例#4
0
/**
 * @brief Export content of the specified datastore for the given module into a file
 * referenced by the descriptor 'fd_out'
 */
static int
srcfg_export_datastore(struct ly_ctx *ly_ctx, int fd_out, const char *module_name, LYD_FORMAT format)
{
    int rc = SR_ERR_INTERNAL;
    struct lyd_node *data_tree = NULL;
    int ret = 0;

    CHECK_NULL_ARG2(ly_ctx, module_name);

    /* get data tree of currently stored configuration */
    rc = srcfg_get_module_data(ly_ctx, module_name, &data_tree);
    if (SR_ERR_OK != rc) {
        goto cleanup;
    }

    /* dump data */
    ret = lyd_print_fd(fd_out, data_tree, format, LYP_WITHSIBLINGS | LYP_FORMAT);
    CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Unable to print the data: %s", ly_errmsg());

    rc = SR_ERR_OK;

cleanup:
    if (NULL != data_tree) {
        lyd_free_withsiblings(data_tree);
    }
    return rc;
}
示例#5
0
/**
 * @brief Import content of the specified datastore for the given module from a file
 * referenced by the descriptor 'fd_in'
 */
static int
srcfg_import_datastore(struct ly_ctx *ly_ctx, int fd_in, const char *module_name, srcfg_datastore_t datastore,
                       LYD_FORMAT format, bool permanent)
{
    int rc = SR_ERR_INTERNAL;
    unsigned i = 0;
    struct lyd_node *new_data_tree = NULL;
    struct lyd_node *current_data_tree = NULL;
    struct lyd_difflist *diff = NULL;
    char *first_xpath = NULL, *second_xpath = NULL;
    char *input_data = NULL;
    int ret = 0;
    struct stat info;

    CHECK_NULL_ARG2(ly_ctx, module_name);

    /* parse input data */
    ret = fstat(fd_in, &info);
    CHECK_NOT_MINUS1_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup,
                              "Unable to obtain input file info: %s.", sr_strerror_safe(errno));
    ly_errno = LY_SUCCESS;
    if (S_ISREG(info.st_mode)) {
        /* load (using mmap) and parse the input data in one step */
        new_data_tree = lyd_parse_fd(ly_ctx, fd_in, format, LYD_OPT_STRICT | LYD_OPT_CONFIG);
    } else { /* most likely STDIN */
        /* load input data into the memory first */
        ret = srcfg_read_file_content(fd_in, &input_data);
        CHECK_RC_MSG_GOTO(ret, cleanup, "Unable to read the input data.");
        /* parse the input data stored inside memory buffer */
        new_data_tree = lyd_parse_mem(ly_ctx, input_data, format, LYD_OPT_STRICT | LYD_OPT_CONFIG);
    }
    if (NULL == new_data_tree && LY_SUCCESS != ly_errno) {
        SR_LOG_ERR("Unable to parse the input data: %s", ly_errmsg());
        goto cleanup;
    }

    /* validate input data */
    if (NULL != new_data_tree) {
        ret = lyd_validate(&new_data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG);
        CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Input data are not valid: %s", ly_errmsg());
    }

    /* remove default nodes */
    lyd_wd_cleanup(&new_data_tree, 0);

    /* get data tree of currently stored configuration */
    rc = srcfg_get_module_data(ly_ctx, module_name, &current_data_tree);
    if (SR_ERR_OK != rc) {
        goto cleanup;
    }

    /* get the list of changes made by the user */
    diff = lyd_diff(current_data_tree, new_data_tree, 0);
    if (NULL == diff) {
        SR_LOG_ERR("Unable to get the list of changes: %s", ly_errmsg());
        goto cleanup;
    }

    /* iterate over the list of differences and for each issue corresponding Sysrepo command(s) */
    while (diff->type && LYD_DIFF_END != diff->type[i]) {
        if (NULL != diff->first[i]) {
            first_xpath = lyd_path(diff->first[i]);
            if (NULL == first_xpath) {
                SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                goto cleanup;
            }
        }
        if (NULL != diff->second[i]) {
            second_xpath = lyd_path(diff->second[i]);
            if (NULL == second_xpath) {
                free(first_xpath);
                first_xpath = NULL;
                SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                goto cleanup;
            }
        }
        switch (diff->type[i]) {
            case LYD_DIFF_DELETED:
                SR_LOG_DBG("<LYD_DIFF_DELETED> node: %s", first_xpath);
                rc = srcfg_convert_lydiff_deleted(first_xpath);
                break;
            case LYD_DIFF_CHANGED:
                SR_LOG_DBG("<LYD_DIFF_CHANGED> orig: %s, new: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_changed(first_xpath, diff->second[i]);
                break;
            case LYD_DIFF_MOVEDAFTER1:
                SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER1> moved: %s, after: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_movedafter(first_xpath, second_xpath);
                break;
            case LYD_DIFF_CREATED:
                SR_LOG_DBG("<LYD_DIFF_CREATED> parent: %s, new node: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_created(diff->second[i]);
                break;
            case LYD_DIFF_MOVEDAFTER2:
                SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER2> after: %s, this new node was inserted: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_movedafter(second_xpath, first_xpath);
                break;
            default:
                assert(0 && "not reachable");
        }
        free(first_xpath);
        free(second_xpath);
        first_xpath = second_xpath = NULL;
        if (SR_ERR_OK != rc) {
            goto cleanup;
        }
        ++i;
    }
    if (0 == i) {
        SR_LOG_DBG_MSG("No changes were made.");
    } else {
        /* commit the changes */
        rc = sr_commit(srcfg_session);
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error returned from sr_commit: %s.", sr_strerror(rc));
            goto cleanup;
        }
        if (SRCFG_STORE_RUNNING == datastore && permanent) {
            /* copy running datastore data into the startup datastore */
            rc = sr_copy_config(srcfg_session, module_name, SR_DS_RUNNING, SR_DS_STARTUP);
            if (SR_ERR_OK != rc) {
                SR_LOG_ERR("Error returned from sr_copy_config: %s.", sr_strerror(rc));
                goto cleanup;
            }
        }
    }

    rc = SR_ERR_OK;

cleanup:
    if (NULL != diff) {
        lyd_free_diff(diff);
    }
    if (NULL != current_data_tree) {
        lyd_free_withsiblings(current_data_tree);
    }
    if (NULL != new_data_tree) {
        lyd_free_withsiblings(new_data_tree);
    }
    if (input_data) {
        free(input_data);
    }
    return rc;
}
示例#6
0
/**
 * @brief Convert data tree difference of type LYD_DIFF_CREATED to corresponding set of Sysrepo public API calls.
 */
static int
srcfg_convert_lydiff_created(struct lyd_node *node)
{
    int rc = SR_ERR_INTERNAL;
    struct lyd_node *elem = node;
    bool process_children = true;
    sr_val_t value = { 0, SR_UNKNOWN_T };
    struct lyd_node_leaf_list *data_leaf = NULL;
    struct lys_node_list *slist = NULL;
    char *xpath = NULL, *delim = NULL;

    CHECK_NULL_ARG(node);

    /* non-recursive DFS post-order */
    do {
        /* go as deep as possible */
        if (process_children) {
            while (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) && elem->child) {
                elem = elem->child;
            }
        }

        /* get appropriate xpath and value */
        free(xpath);
        xpath = value.xpath = NULL;
        value.type = SR_UNKNOWN_T;
        switch (elem->schema->nodetype) {
            case LYS_LEAF: /* e.g.: /test-module:user[name='nameE']/name */
                /* get value */
                data_leaf = (struct lyd_node_leaf_list *)elem;
                value.type = sr_libyang_leaf_get_type(data_leaf);
                rc = sr_libyang_leaf_copy_value(data_leaf, &value);
                if (SR_ERR_OK != rc) {
                    SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc));
                    goto cleanup;
                }
                /* get xpath */
                xpath = lyd_path(elem);
                if (NULL == xpath) {
                    SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                    goto cleanup;
                }
                /* key value of a list cannot be set directly */
                if (elem->parent && (elem->parent->schema->nodetype == LYS_LIST)) {
                    slist = (struct lys_node_list *)elem->parent->schema;
                    for (unsigned i = 0; i < slist->keys_size; ++i) {
                        if (slist->keys[i]->name == elem->schema->name) {
                            /* key */
                            if (i == 0) {
                                delim = strrchr(xpath, '/');
                                if (delim) {
                                    *delim = '\0';
                                }
                                goto set_value;
                            } else {
                                /* create list instance (directly) only once - with the first key */
                                goto next_node;
                            }
                        }
                    }
                }
                break;

            case LYS_LEAFLIST: /* e.g.: /test-module:main/numbers[.='10'] */
                /* get value */
                data_leaf = (struct lyd_node_leaf_list *)elem;
                value.type = sr_libyang_leaf_get_type(data_leaf);
                rc = sr_libyang_leaf_copy_value(data_leaf, &value);
                if (SR_ERR_OK != rc) {
                    SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc));
                    goto cleanup;
                }
                /* get xpath */
                xpath = lyd_path(elem);
                if (NULL == xpath) {
                    SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                    goto cleanup;
                }
                /* strip away the predicate */
                delim = strrchr(xpath, '[');
                if (delim) {
                    *delim = '\0';
                }
                break;

            case LYS_ANYXML:
                SR_LOG_ERR_MSG("The anyxml statement is not yet supported by Sysrepo.");
                goto cleanup;

            case LYS_CONTAINER:
                /* explicitly create only presence containers */
                if (((struct lys_node_container *)elem->schema)->presence) {
                    xpath = lyd_path(elem);
                } else {
                    goto next_node;
                }
                break;

            default:
                /* no data to set */
                goto next_node;
        }

set_value:
        /* set value */
        rc = sr_set_item(srcfg_session, xpath, SR_UNKNOWN_T != value.type ? &value : NULL, SR_EDIT_DEFAULT);
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error returned from sr_set_item: %s.", sr_strerror(rc));
            goto cleanup;
        }

next_node:
        /* backtracking + automatically moving to the next sibling if there is any */
        if (elem != node) {
            if (elem->next) {
                elem = elem->next;
                process_children = true;
            } else {
                assert(elem->parent);
                elem = elem->parent;
                process_children = false;
            }
        } else {
            break;
        }
    } while (true);

    rc = SR_ERR_OK;

cleanup:
    if (NULL != xpath) {
        free(xpath);
    }
    sr_free_val_content(&value);
    return rc;
}
示例#7
0
/**
 * @brief Get complete libyang data tree of a specified module from sysrepo.
 */
static int
srcfg_get_module_data(struct ly_ctx *ly_ctx, const char *module_name, struct lyd_node **data_tree)
{
    int rc = SR_ERR_OK, ret = 0;
    sr_val_t *value = NULL;
    sr_val_iter_t *iter = NULL;
    struct lyd_node *node = NULL;
    const struct lys_node *schema = NULL;
    char query[PATH_MAX] = { 0, };
    char *string_val = NULL;

    snprintf(query, PATH_MAX, "/%s:*//.", module_name);
    rc = sr_get_items_iter(srcfg_session, query, &iter);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Error by sr_get_items_iter: %s", sr_strerror(rc));
        goto cleanup;
    }

    *data_tree = NULL;
    ly_errno = LY_SUCCESS;
    ly_diminish_errors = true;
    while (SR_ERR_OK == (rc = sr_get_item_next(srcfg_session, iter, &value))) {
        ly_diminish_errors = false;
        if (NULL == value) {
            goto next;
        }
        /* get node schema */
        schema = ly_ctx_get_node2(ly_ctx, NULL, value->xpath, 0);
        if (!schema) {
            SR_LOG_ERR("Error by ly_ctx_get_node2: %s", ly_errmsg());
            goto fail;
        }

        /* skip default values */
        if (schema->nodetype == LYS_LEAF && value->dflt) {
            goto next;
        }

        /* skip non-presence containers */
        if (value->type == SR_CONTAINER_T) {
            goto next;
        }

        /* convert value to string */
        rc = sr_val_to_str(value, schema, &string_val);
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error by sr_val_to_str: %s", sr_strerror(rc));
            goto fail;
        }

        /* add node to data tree */
        ly_errno = LY_SUCCESS;
        node = lyd_new_path(*data_tree, ly_ctx, value->xpath, string_val, LYD_PATH_OPT_UPDATE);
        if (!node && LY_SUCCESS != ly_errno) {
            SR_LOG_ERR("Error by lyd_new_path: %s", ly_errmsg());
            goto fail;
        }
        if (NULL == *data_tree) {
            *data_tree = node;
        }
next:
        /* cleanup before next iteration */
        if (NULL != string_val) {
            free(string_val);
            string_val = NULL;
        }
        if (NULL != value) {
            sr_free_val(value);
            value = NULL;
        }
        ly_diminish_errors = true;
    }
    ly_diminish_errors = false;

    if (SR_ERR_NOT_FOUND == rc) {
        rc = SR_ERR_OK;
    }
    if (SR_ERR_OK == rc) {
        if (NULL != *data_tree) {
            /* validate returned data, but most importantly resolve leafrefs */
            ret = lyd_validate(data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG);
            CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, fail, "Received data tree from sysrepo is not valid: %s", ly_errmsg());
            /* remove default nodes added by validation */
            lyd_wd_cleanup(data_tree, 0);
        }
        goto cleanup;
    }

fail:
    rc = SR_ERR_INTERNAL;
    if (NULL != *data_tree) {
        lyd_free_withsiblings(*data_tree);
        *data_tree = NULL;
    }

cleanup:
    if (NULL != string_val) {
        free(string_val);
    }
    if (NULL != value) {
        sr_free_val(value);
    }
    if (NULL != iter) {
        sr_free_val_iter(iter);
    }
    return rc;
}
示例#8
0
/**
 * @brief Initializes libyang ctx with all schemas installed for specified module in sysrepo.
 */
static int
srcfg_ly_init(struct ly_ctx **ly_ctx, const char *module_name)
{
    DIR *dp = NULL;
    struct dirent *ep = NULL;
    char *delim = NULL;
    char schema_filename[PATH_MAX] = { 0, };
    const struct lys_module *module = NULL;

    CHECK_NULL_ARG2(ly_ctx, module_name);

    *ly_ctx = ly_ctx_new(srcfg_schema_search_dir);
    if (NULL == *ly_ctx) {
        SR_LOG_ERR("Unable to initialize libyang context: %s", ly_errmsg());
        return SR_ERR_INTERNAL;
    }
    ly_set_log_clb(srcfg_ly_log_cb, 1);

    /* iterate over all files in the directory with schemas */
    dp = opendir(srcfg_schema_search_dir);
    if (NULL == dp) {
        SR_LOG_ERR("Failed to open the schema directory: %s.", sr_strerror_safe(errno));
        return SR_ERR_INTERNAL;
    }
    while (NULL != (ep = readdir(dp))) {
        /* test file extension */
        LYS_INFORMAT fmt = LYS_IN_UNKNOWN;
        if (sr_str_ends_with(ep->d_name, SR_SCHEMA_YIN_FILE_EXT)) {
            fmt = LYS_IN_YIN;
        } else if (sr_str_ends_with(ep->d_name, SR_SCHEMA_YANG_FILE_EXT)) {
            fmt = LYS_IN_YANG;
        }
        if (fmt != LYS_IN_UNKNOWN) {
            /* strip extension and revision */
            strcpy(schema_filename, ep->d_name);
            delim = strrchr(schema_filename, '.');
            assert(delim);
            *delim = '\0';
            delim = strrchr(schema_filename, '@');
            if (delim) {
                *delim = '\0';
            }
            /* TODO install all revisions and dependencies of the specified module, but not more */
#if 0 /* XXX install all schemas until we can resolve all dependencies */
            if (strcmp(schema_filename, module_name) == 0) {
#endif
                /* construct full file path */
                snprintf(schema_filename, PATH_MAX, "%s%s", srcfg_schema_search_dir, ep->d_name);
                /* load the schema into the context */
                SR_LOG_DBG("Loading module schema: '%s'.", schema_filename);
                module = lys_parse_path(*ly_ctx, schema_filename, fmt);
                if (NULL == module) {
                    continue;
                }
                for (uint8_t i = 0; i < module->features_size; i++) {
                    lys_features_enable(module, module->features[i].name);
                }
#if 0
            }
#endif
        }
    }
    closedir(dp);

    return SR_ERR_OK;
}
示例#9
0
static void
test_parse_noncharacters_xml(void **state)
{
    struct state *st;
    const char* mod = "module x {namespace urn:x; prefix x; leaf x { type string;}}";
    const char* data = "<x xmlns=\"urn:x\">----------</x>";

    assert_ptr_not_equal(((*state) = st = calloc(1, sizeof *st)), NULL);
    assert_ptr_not_equal((st->ctx = ly_ctx_new(NULL)), NULL);

    /* test detection of invalid characters according to RFC 7950, sec 9.4 */
    assert_ptr_not_equal(lys_parse_mem(st->ctx, mod, LYS_IN_YANG), 0);
    assert_ptr_not_equal((st->str1 = strdup(data)), NULL);

    /* exclude surrogate blocks 0xD800-DFFF - trying 0xd800 */
    st->str1[17] = 0xed;
    st->str1[18] = 0xa0;
    st->str1[19] = 0x80;
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INCHAR);
    assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0000d800");

    /* exclude noncharacters %xFDD0-FDEF - trying 0xfdd0 */
    st->str1[17] = 0xef;
    st->str1[18] = 0xb7;
    st->str1[19] = 0x90;
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INCHAR);
    assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0000fdd0");

    /* exclude noncharacters %xFFFE-FFFF - trying 0xfffe */
    st->str1[17] = 0xef;
    st->str1[18] = 0xbf;
    st->str1[19] = 0xbe;
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INCHAR);
    assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0000fffe");

    /* exclude c0 control characters except tab, carriage return and line feed */
    st->str1[17] = 0x9; /* valid - horizontal tab */
    st->str1[18] = 0xa; /* valid - new line */
    st->str1[19] = 0xd; /* valid - carriage return */
    st->str1[20] = 0x6; /* invalid - ack */
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INCHAR);
    assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x06");

    /* exclude noncharacters %x?FFFE-?FFFF - trying 0x10ffff */
    st->str1[17] = 0xf4;
    st->str1[18] = 0x8f;
    st->str1[19] = 0xbf;
    st->str1[20] = 0xbf;
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INCHAR);
    assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0010ffff");

    /* 0x6 */
    st->str1[17] = '&';
    st->str1[18] = '#';
    st->str1[19] = 'x';
    st->str1[20] = '6';
    st->str1[21] = ';';
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INVAL);
    assert_string_equal(ly_errmsg(), "Invalid character reference value.");

    /* 0xdfff */
    st->str1[17] = '&';
    st->str1[18] = '#';
    st->str1[19] = 'x';
    st->str1[20] = 'd';
    st->str1[21] = 'f';
    st->str1[22] = 'f';
    st->str1[23] = 'f';
    st->str1[24] = ';';
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INVAL);
    assert_string_equal(ly_errmsg(), "Invalid character reference value.");

    /* 0xfdef */
    st->str1[17] = '&';
    st->str1[18] = '#';
    st->str1[19] = 'x';
    st->str1[20] = 'f';
    st->str1[21] = 'd';
    st->str1[22] = 'e';
    st->str1[23] = 'f';
    st->str1[24] = ';';
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INVAL);
    assert_string_equal(ly_errmsg(), "Invalid character reference value.");

    /* 0xffff */
    st->str1[17] = '&';
    st->str1[18] = '#';
    st->str1[19] = 'x';
    st->str1[20] = 'f';
    st->str1[21] = 'f';
    st->str1[22] = 'f';
    st->str1[23] = 'f';
    st->str1[24] = ';';
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INVAL);
    assert_string_equal(ly_errmsg(), "Invalid character reference value.");

    /* the same using character reference */
    /* 0x10ffff */
    st->str1[17] = '&';
    st->str1[18] = '#';
    st->str1[19] = 'x';
    st->str1[20] = '1';
    st->str1[21] = '0';
    st->str1[22] = 'f';
    st->str1[23] = 'f';
    st->str1[24] = 'f';
    st->str1[25] = 'f';
    st->str1[26] = ';';
    assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL);
    assert_int_equal(ly_errno, LY_EVALID);
    assert_int_equal(ly_vecode, LYVE_XML_INVAL);
    assert_string_equal(ly_errmsg(), "Invalid character reference value.");

}