1
0
Fork 0

Adding upstream version 3.1.0+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 08:00:08 +01:00
parent 64dbec996d
commit cfcebb1a7d
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
569 changed files with 205393 additions and 0 deletions

File diff suppressed because it is too large Load diff

2841
tests/utests/data/test_lyb.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,756 @@
/**
* @file test_merge.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief tests for complex data merges.
*
* Copyright (c) 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _UTEST_MAIN_
#include "utests.h"
#include "libyang.h"
#define LYD_TREE_CREATE(INPUT, MODEL) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL)
#define CONTEXT_CREATE \
CONTEXT_CREATE_PATH(NULL)
#define LYD_TREE_CHECK_CHAR(MODEL, TEXT, PARAMS) \
CHECK_LYD_STRING_PARAM(MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS | PARAMS)
static void
test_batch(void **state)
{
const char *start =
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2016-02-11</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n";
const char *data[] = {
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-yang-library</name>\n"
" <revision>2016-02-01</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-acm</name>\n"
" <revision>2012-02-22</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf</name>\n"
" <revision>2011-06-01</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-monitoring</name>\n"
" <revision>2010-10-04</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-with-defaults</name>\n"
" <revision>2011-06-01</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2016-02-11</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-yang-library</name>\n"
" <revision>2016-02-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-acm</name>\n"
" <revision>2012-02-22</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf</name>\n"
" <revision>2011-06-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n"
" <feature>writable-running</feature>\n"
" <feature>candidate</feature>\n"
" <feature>rollback-on-error</feature>\n"
" <feature>validate</feature>\n"
" <feature>startup</feature>\n"
" <feature>xpath</feature>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-monitoring</name>\n"
" <revision>2010-10-04</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-with-defaults</name>\n"
" <revision>2011-06-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n"
};
const char *output_template =
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2016-02-11</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-yang-library</name>\n"
" <revision>2016-02-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-netconf-acm</name>\n"
" <revision>2012-02-22</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-netconf</name>\n"
" <revision>2011-06-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n"
" <feature>writable-running</feature>\n"
" <feature>candidate</feature>\n"
" <feature>rollback-on-error</feature>\n"
" <feature>validate</feature>\n"
" <feature>startup</feature>\n"
" <feature>xpath</feature>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-netconf-monitoring</name>\n"
" <revision>2010-10-04</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-netconf-with-defaults</name>\n"
" <revision>2011-06-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n";
struct lyd_node *target;
CHECK_PARSE_LYD_PARAM(start, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, target);
for (int32_t i = 0; i < 11; ++i) {
struct lyd_node *source;
CHECK_PARSE_LYD_PARAM(data[i], LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, source);
assert_int_equal(LY_SUCCESS, lyd_merge_siblings(&target, source, LYD_MERGE_DESTRUCT));
}
LYD_TREE_CHECK_CHAR(target, output_template, 0);
lyd_free_all(target);
}
static void
test_leaf(void **state)
{
const char *sch = "module x {"
" namespace urn:x;"
" prefix x;"
" container A {"
" leaf f1 {type string;}"
" container B {"
" leaf f2 {type string;}"
" }"
" }"
" }";
const char *trg = "<A xmlns=\"urn:x\"> <f1>block</f1> </A>";
const char *src = "<A xmlns=\"urn:x\"> <f1>aa</f1> <B> <f2>bb</f2> </B> </A>";
const char *result = "<A xmlns=\"urn:x\"><f1>aa</f1><B><f2>bb</f2></B></A>";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, LYD_PRINT_SHRINK);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_container(void **state)
{
const char *sch =
"module A {\n"
" namespace \"aa:A\";\n"
" prefix A;\n"
" container A {\n"
" leaf f1 {type string;}\n"
" container B {\n"
" leaf f2 {type string;}\n"
" }\n"
" container C {\n"
" leaf f3 {type string;}\n"
" }\n"
" }\n"
"}\n";
const char *trg = "<A xmlns=\"aa:A\"> <B> <f2>aaa</f2> </B> </A>";
const char *src = "<A xmlns=\"aa:A\"> <C> <f3>bbb</f3> </C> </A>";
const char *result = "<A xmlns=\"aa:A\"><B><f2>aaa</f2></B><C><f3>bbb</f3></C></A>";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, LYD_PRINT_SHRINK);
/* destroy */
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_list(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" list b-list1 {\n"
" key p1;\n"
" leaf p1 {\n"
" type uint8;\n"
" }\n"
" leaf p2 {\n"
" type string;\n"
" }\n"
" leaf p3 {\n"
" type boolean;\n"
" default false;\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <p3>true</p3>\n"
" </b-list1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" <p3>true</p3>\n"
" </b-list1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_list2(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" list b-list1 {\n"
" key p1;\n"
" leaf p1 {\n"
" type uint8;\n"
" }\n"
" leaf p2 {\n"
" type string;\n"
" }\n"
" container inner2 {\n"
" leaf p3 {\n"
" type boolean;\n"
" default false;\n"
" }\n"
" leaf p4 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_dup_inst_list(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" config false;\n"
" list b-list1 {\n"
" leaf p1 {\n"
" type uint8;\n"
" }\n"
" leaf p2 {\n"
" type string;\n"
" }\n"
" container inner2 {\n"
" leaf p4 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>2</p1>\n"
" <p2>a</p2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>2</p1>\n"
" <p2>a</p2>\n"
" </b-list1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_dup_inst_llist(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" config false;\n"
" leaf-list b-llist1 {\n"
" type string;\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_case(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
" container cont {\n"
" choice ch {\n"
" container inner {\n"
" leaf p1 {\n"
" type string;\n"
" }\n"
" }\n"
" case c2 {\n"
" leaf p1 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<cont xmlns=\"http://test/merge\">\n"
" <inner>\n"
" <p1>1</p1>\n"
" </inner>\n"
"</cont>\n";
const char *src =
"<cont xmlns=\"http://test/merge\">\n"
" <p1>1</p1>\n"
"</cont>\n";
const char *result =
"<cont xmlns=\"http://test/merge\">\n"
" <p1>1</p1>\n"
"</cont>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_dflt(void **state)
{
const char *sch =
"module merge-dflt {\n"
" namespace \"urn:merge-dflt\";\n"
" prefix md;\n"
" container top {\n"
" leaf a {\n"
" type string;\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" default \"c_dflt\";\n"
" }\n"
" }\n"
"}\n";
struct lyd_node *target = NULL;
struct lyd_node *source = NULL;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/c", "c_dflt", 0, &target), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/a", "a_val", 0, &source), LY_SUCCESS);
assert_int_equal(lyd_new_path(source, UTEST_LYCTX, "/merge-dflt:top/b", "b_val", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&source, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_merge_siblings(&target, source, LYD_MERGE_DESTRUCT | LYD_MERGE_DEFAULTS), LY_SUCCESS);
source = NULL;
/* c should be replaced and now be default */
assert_string_equal(lyd_child(target)->prev->schema->name, "c");
assert_true(lyd_child(target)->prev->flags & LYD_DEFAULT);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_dflt2(void **state)
{
const char *sch =
"module merge-dflt {\n"
" namespace \"urn:merge-dflt\";\n"
" prefix md;\n"
" container top {\n"
" leaf a {\n"
" type string;\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" default \"c_dflt\";\n"
" }\n"
" }\n"
"}\n";
struct lyd_node *target;
struct lyd_node *source;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/c", "c_dflt", 0, &target), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/a", "a_val", 0, &source), LY_SUCCESS);
assert_int_equal(lyd_new_path(source, UTEST_LYCTX, "/merge-dflt:top/b", "b_val", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&source, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
/* c should not be replaced, so c remains not default */
assert_false(lyd_child(target)->flags & LYD_DEFAULT);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_leafrefs(void **state)
{
const char *sch = "module x {"
" namespace urn:x;"
" prefix x;"
" list l {"
" key n;"
" leaf n { type string; }"
" leaf t { type string; }"
" leaf r { type leafref { path '/l/n'; } }}}";
const char *trg = "<l xmlns=\"urn:x\"><n>a</n></l>"
"<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>";
const char *src = "<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>"
"<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>";
const char *res = "<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>"
"<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>"
"<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
LYD_TREE_CHECK_CHAR(target, res, LYD_PRINT_SHRINK);
lyd_free_all(source);
lyd_free_all(target);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_batch),
UTEST(test_leaf),
UTEST(test_container),
UTEST(test_list),
UTEST(test_list2),
UTEST(test_dup_inst_list),
UTEST(test_dup_inst_llist),
UTEST(test_case),
UTEST(test_dflt),
UTEST(test_dflt2),
UTEST(test_leafrefs),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,536 @@
/**
* @file test_new.c
* @author: Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for functions for creating data
*
* Copyright (c) 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _UTEST_MAIN_
#include "utests.h"
#include "libyang.h"
/* common module for the tests */
const char *schema_a = "module a {\n"
" namespace urn:tests:a;\n"
" prefix a;yang-version 1.1;\n"
" list l1 {\n"
" key \"a b\";\n"
" leaf a {\n"
" type string;\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" }\n"
" }\n"
" list l11 {\n"
" key \"a\";\n"
" leaf a {\n"
" type uint32;\n"
" }\n"
" leaf b {\n"
" type uint32;\n"
" }\n"
" }\n"
" leaf foo {\n"
" type uint16;\n"
" }\n"
" leaf-list ll {\n"
" type string;\n"
" }\n"
" container c {\n"
" leaf-list x {\n"
" type string;\n"
" }\n"
" }\n"
" anydata any {\n"
" config false;\n"
" }\n"
" anyxml anyx;\n"
" leaf-list ll2 {\n"
" config false;\n"
" type string;\n"
" }\n"
" list l2 {\n"
" config false;\n"
" container c {\n"
" leaf x {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" container c2 {\n"
" config false;\n"
" list l3 {\n"
" leaf x {\n"
" type string;\n"
" }\n"
" leaf y {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" rpc oper {\n"
" input {\n"
" leaf param {\n"
" type string;\n"
" }\n"
" }\n"
" output {\n"
" leaf param {\n"
" type int8;\n"
" }\n"
" }\n"
" }\n"
"}\n";
static void
test_top_level(void **state)
{
struct lys_module *mod;
struct lyd_node *node, *rpc;
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
/* list */
assert_int_equal(lyd_new_list(NULL, mod, "l1", 0, &node, "val_a", "val_b"), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[]", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Unexpected XPath token \"]\" (\"]\").", "/a:l1", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[key1='a'][key2='b']", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Not found node \"key1\" in path.", "/a:l1", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Key expected instead of leaf \"c\" in path.", "/a:l1", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "c", "[a='a'][b='b']", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("List node \"c\" not found.", NULL, 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a='a'][b='b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a=''][b='']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a:a='a'][a:b='b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a= 'a']\n[b =\t'b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
const char *key_vals[] = {"a", "b"};
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, NULL, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
uint32_t val_lens[] = {1, 1};
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_BIN, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_CANON, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_CANON | LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list3()).", NULL, 0);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_BIN, &node, "val_a", 5, "val_b", 5), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_BIN | LYD_NEW_VAL_STORE_ONLY, &node, "val_a", 5, "val_b", 5), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list()).", NULL, 0);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_CANON, &node, "val_a", "val_b"), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_CANON | LYD_NEW_VAL_STORE_ONLY, &node, "val_a", "val_b"), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list()).", NULL, 0);
/* leaf */
assert_int_equal(lyd_new_term(NULL, mod, "foo", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Invalid type uint16 value \"[a='a'][b='b'][c='c']\".", "/a:foo", 0);
assert_int_equal(lyd_new_term(NULL, mod, "c", "value", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Term node \"c\" not found.", NULL, 0);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "256", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_BIN, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(options & 0x04) (lyd_new_term()).", NULL, 0);
assert_int_equal(lyd_new_term_bin(NULL, mod, "foo", "25", 2, LYD_NEW_VAL_BIN, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_term_bin(NULL, mod, "foo", "25", 2, LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_term()).", NULL, 0);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_CANON, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_CANON | LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_term()).", NULL, 0);
/* leaf-list */
assert_int_equal(lyd_new_term(NULL, mod, "ll", "ahoy", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* container */
assert_int_equal(lyd_new_inner(NULL, mod, "c", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_inner(NULL, mod, "l1", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l1\" not found.", NULL, 0);
assert_int_equal(lyd_new_inner(NULL, mod, "l2", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l2\" not found.", NULL, 0);
/* anydata */
assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_any(NULL, mod, "any", "<node>val</node>", LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* key-less list */
assert_int_equal(lyd_new_list2(NULL, mod, "l2", "[a='a'][b='b']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("List predicate defined for keyless list \"l2\" in path.", "/a:l2", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l2", "", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l2", NULL, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list(NULL, mod, "l2", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* RPC */
assert_int_equal(lyd_new_inner(NULL, mod, "oper", 0, &rpc), LY_SUCCESS);
assert_int_equal(lyd_new_term(rpc, mod, "param", "22", 0, &node), LY_SUCCESS);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_node_leaf *)node->schema)->type->basetype);
assert_int_equal(lyd_new_term(rpc, mod, "param", "22", LYD_NEW_VAL_OUTPUT, &node), LY_SUCCESS);
assert_int_equal(LY_TYPE_INT8, ((struct lysc_node_leaf *)node->schema)->type->basetype);
lyd_free_tree(rpc);
}
static void
test_opaq(void **state)
{
struct lyd_node *root, *node;
struct lyd_node_opaq *opq;
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, NULL);
assert_int_equal(lyd_new_opaq(NULL, UTEST_LYCTX, "node1", NULL, NULL, "my-module", &root), LY_SUCCESS);
assert_null(root->schema);
opq = (struct lyd_node_opaq *)root;
assert_string_equal(opq->name.name, "node1");
assert_string_equal(opq->name.module_name, "my-module");
assert_string_equal(opq->value, "");
assert_int_equal(lyd_new_opaq(root, NULL, "node2", "value", NULL, "my-module2", &node), LY_SUCCESS);
assert_null(node->schema);
opq = (struct lyd_node_opaq *)node;
assert_string_equal(opq->name.name, "node2");
assert_string_equal(opq->name.module_name, "my-module2");
assert_string_equal(opq->value, "value");
assert_ptr_equal(opq->parent, root);
lyd_free_tree(root);
}
static void
test_path(void **state)
{
LY_ERR ret;
struct lyd_node *root, *node, *parent;
struct lys_module *mod;
char *str;
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
/* create 2 nodes */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c/x[.='val']", "vvv", 0, 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(root->schema->name, "c");
assert_non_null(node);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val", lyd_get_value(node));
/* append another */
ret = lyd_new_path2(root, NULL, "/a:c/x", "val2", 0, 0, 0, &parent, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_ptr_equal(parent, node);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val2", lyd_get_value(node));
/* and a last one */
ret = lyd_new_path2(root, NULL, "x", "val3", 0, 0, 0, &parent, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_ptr_equal(parent, node);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val3", lyd_get_value(node));
lyd_free_tree(root);
/* try LYD_NEWOPT_OPAQ */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, 0, NULL, NULL);
assert_int_equal(ret, LY_EINVAL);
CHECK_LOG_CTX("Predicate missing for list \"l1\" in path \"/a:l1\".", "/a:l1", 0);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_null(root->schema);
lyd_free_tree(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, 0, NULL, NULL);
assert_int_equal(ret, LY_EVALID);
CHECK_LOG_CTX("Invalid type uint16 empty value.", "/a:foo", 0);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_null(root->schema);
lyd_free_tree(root);
ret = lyd_new_path(NULL, UTEST_LYCTX, "/a:l11", NULL, LYD_NEW_PATH_OPAQ, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_null(root->schema);
ret = lyd_new_path(root, NULL, "a", NULL, LYD_NEW_PATH_OPAQ, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(lyd_child(root));
assert_null(lyd_child(root)->schema);
ret = lyd_new_path(root, NULL, "b", NULL, LYD_NEW_PATH_OPAQ, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(lyd_child(root)->next);
assert_null(lyd_child(root)->next->schema);
lyd_free_tree(root);
/* key-less list */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c2/l3/x", "val1", 0, 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val1", lyd_get_value(node));
ret = lyd_new_path2(root, NULL, "/a:c2/l3[1]", NULL, 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
CHECK_LOG_CTX("Path \"/a:c2/l3[1]\" already exists.", "/a:c2/l3[1]", 0);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[2]/x", "val2", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
ret = lyd_new_path2(root, NULL, "/a:c2/l3/x", "val3", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "empty", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "val4", 0, 0, LYD_NEW_PATH_UPDATE, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[5]/x", "val5", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[6]/x", "val6", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<c2 xmlns=\"urn:tests:a\">\n"
" <l3>\n"
" <x>val1</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val2</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val3</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val4</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val5</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val6</x>\n"
" </l3>\n"
"</c2>\n");
free(str);
lyd_free_siblings(root);
/* state leaf-list */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:ll2", "val_first", 0, 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(node->schema->name, "ll2");
assert_string_equal("val_first", lyd_get_value(node));
ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
CHECK_LOG_CTX("Path \"/a:ll2[1]\" already exists.", "/a:ll2[1]", 0);
ret = lyd_new_path2(root, NULL, "/a:ll2[2]", "val2", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "val", 0, 0, LYD_NEW_PATH_UPDATE, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, UTEST_LYCTX, "/a:ll2", "val3", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:ll2[3][.='val3']", NULL, 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EVALID);
CHECK_LOG_CTX("Unparsed characters \"[.='val3']\" left at the end of path.", NULL, 0);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<ll2 xmlns=\"urn:tests:a\">val</ll2>\n"
"<ll2 xmlns=\"urn:tests:a\">val2</ll2>\n"
"<ll2 xmlns=\"urn:tests:a\">val3</ll2>\n");
free(str);
lyd_free_siblings(root);
/* anydata */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", "<elem>val</elem>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<any xmlns=\"urn:tests:a\">\n"
" <elem>val</elem>\n"
"</any>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:any\": {\n"
" \"elem\": \"val\"\n"
" }\n"
"}\n");
free(str);
lyd_free_siblings(root);
/* anyxml */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "<a/><b/><c/>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">\n"
" <a/>\n"
" <b/>\n"
" <c/>\n"
"</anyx>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:anyx\": {\n"
" \"a\": [null],\n"
" \"b\": [null],\n"
" \"c\": [null]\n"
" }\n"
"}\n");
free(str);
lyd_free_siblings(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "{\"a\":[null],\"b\":[null],\"c\":[null]}", 0, LYD_ANYDATA_JSON, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">\n"
" <a/>\n"
" <b/>\n"
" <c/>\n"
"</anyx>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:anyx\": {\n"
" \"a\": [null],\n"
" \"b\": [null],\n"
" \"c\": [null]\n"
" }\n"
"}\n");
free(str);
lyd_free_siblings(root);
}
static void
test_path_ext(void **state)
{
LY_ERR ret;
struct lyd_node *root, *node;
struct lys_module *mod;
const char *mod_str = "module ext {yang-version 1.1; namespace urn:tests:extensions:ext; prefix e;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template {container c {leaf x {type string;} leaf y {type string;} leaf z {type string;}}}}";
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-restconf", "2017-01-26", NULL));
UTEST_ADD_MODULE(mod_str, LYS_IN_YANG, NULL, &mod);
/* create x */
ret = lyd_new_ext_path(NULL, &mod->compiled->exts[0], "/ext:c/x", "xxx", 0, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(root->schema->name, "c");
assert_non_null(node = lyd_child(root));
assert_string_equal(node->schema->name, "x");
assert_string_equal("xxx", lyd_get_value(node));
/* append y */
ret = lyd_new_ext_path(root, &mod->compiled->exts[0], "/ext:c/y", "yyy", 0, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_string_equal(node->schema->name, "y");
assert_string_equal("yyy", lyd_get_value(node));
/* append z */
ret = lyd_new_path(root, NULL, "ext:z", "zzz", 0, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_string_equal(node->schema->name, "z");
assert_string_equal("zzz", lyd_get_value(node));
lyd_free_tree(root);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_top_level),
UTEST(test_opaq),
UTEST(test_path),
UTEST(test_path_ext),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,945 @@
/**
* @file test_parser_json.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for JSON parser
*
* Copyright (c) 2019 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _UTEST_MAIN_
#include "utests.h"
#include "context.h"
#include "in.h"
#include "out.h"
#include "parser_data.h"
#include "printer_data.h"
#include "tests_config.h"
#include "tree_data_internal.h"
#include "tree_schema.h"
static int
setup(void **state)
{
const char *schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1; import ietf-yang-metadata {prefix md;}"
"md:annotation hint { type int8;}"
"list l1 { key \"a b c\"; leaf a {type string;} leaf b {type string;} leaf c {type int16;}"
" leaf d {type string;}"
" container cont {leaf e {type boolean;}}"
"}"
"leaf foo { type string;}"
"container c {"
" leaf x {type string;}"
" action act { input { leaf al {type string;} } output { leaf al {type uint8;} } }"
" notification n1 { leaf nl {type string;} }"
"}"
"container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}"
"anydata any {config false;}"
"anyxml axml;"
"leaf-list ll1 { type uint8; }"
"leaf foo2 { type string; default \"default-val\"; }"
"leaf foo3 { type uint32; }"
"leaf foo4 { type uint64; }"
"rpc r1 {input {leaf l1 {type string;} leaf l2 {type string;}}}"
"notification n2;"
"}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
return 0;
}
#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_JSON, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
#define PARSER_CHECK_ERROR(INPUT, PARSE_OPTION, VALIDATE_OPTION, MODEL, RET_VAL, ERR_MESSAGE, ERR_PATH, ERR_LINE) \
assert_int_equal(RET_VAL, lyd_parse_data_mem(UTEST_LYCTX, INPUT, LYD_JSON, PARSE_OPTION, VALIDATE_OPTION, &MODEL));\
CHECK_LOG_CTX(ERR_MESSAGE, ERR_PATH, ERR_LINE);\
assert_null(MODEL)
#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_JSON, PRINT_OPTION)
static void
test_leaf(void **state)
{
struct lyd_node *tree;
struct lyd_node_term *leaf;
const char *data;
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));
data = "{\"a:foo\":\"foo value\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(leaf->value, STRING, "foo value");
CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree->next->next;
CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
assert_true(leaf->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* make foo2 explicit */
data = "{\"a:foo2\":\"default-val\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
assert_false(leaf->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* parse foo2 but make it implicit */
data = "{\"a:foo2\":\"default-val\",\"@a:foo2\":{\"ietf-netconf-with-defaults:default\":true}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
assert_true(leaf->flags & LYD_DEFAULT);
/* print default values */
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL_TAG, data);
lyd_free_all(tree);
/* skip leaf */
data = "{\"a:cp\":{\"x\":\"val\",\"y\":\"valy\",\"z\":5}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:cp\":{\"y\":\"valy\",\"z\":5}}");
lyd_free_all(tree);
/* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
data = "{\"@a:foo\":{\"a:hint\":1,\"a:hint\":2,\"x:xxx\":{\"value\":\"/x:no/x:yes\"}},\"a:foo\":\"xxx\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
CHECK_LYD_META(tree->meta, 1, "hint", 1, 1, INT8, "1", 1);
CHECK_LYD_META(tree->meta->next, 1, "hint", 0, 1, INT8, "2", 2);
assert_null(tree->meta->next->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:foo\":\"xxx\",\"@a:foo\":{\"a:hint\":1,\"a:hint\":2}}");
lyd_free_all(tree);
PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Unknown (or not implemented) YANG module \"x\" of metadata \"x:xxx\".", "/@a:foo", 1);
/* missing referenced metadata node */
PARSER_CHECK_ERROR("{\"@a:foo\" : { \"a:hint\" : 1 }}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Missing JSON data instance to be coupled with @a:foo metadata.", "/@a:foo", 1);
/* missing namespace for meatadata*/
PARSER_CHECK_ERROR("{\"a:foo\" : \"value\", \"@a:foo\" : { \"hint\" : 1 }}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Metadata in JSON must be namespace-qualified, missing prefix for \"hint\".", "/a:foo", 1);
/* invalid JSON type */
data = "{\"a:l1\" : [{ \"a\" : \"val-a\", \"b\" : \"val-b\", \"c\" : 1, \"cont\" : { \"e\" : \"0\" } }]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-boolean-encoded boolean value \"0\".", "/a:l1[a='val-a'][b='val-b'][c='1']/cont/e", 1);
/* reverse solidus in JSON object member name */
data = "{\"@a:foo\":{\"a:hi\\nt\":1},\"a:foo\":\"xxx\"}";
assert_int_equal(LY_EINVAL, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Annotation definition for attribute \"a:hi\nt\" not found.", "/@a:foo/@a:hi\nt", 1);
data = "{\"a:foo\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Invalid non-string-encoded string value \"\".", "/a:foo", 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}
static void
test_leaflist(void **state)
{
const char *data;
struct lyd_node *tree;
struct lyd_node_term *ll;
data = "{\"a:ll1\":[10,11]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(ll->value, UINT8, "10", 10);
assert_non_null(tree->next);
CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next;
CHECK_LYD_VALUE(ll->value, UINT8, "11", 11);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* accept empty */
data = "{\"a:ll1\":[]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
/* simple metadata */
data = "{\"a:ll1\":[10,11],\"@a:ll1\":[null,{\"a:hint\":2}]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(ll->value, UINT8, "10", 10);
assert_non_null(tree->next);
CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next;
CHECK_LYD_VALUE(ll->value, UINT8, "11", 11);
CHECK_LYD_META(ll->meta, 1, "hint", 0, 1, INT8, "2", 2);
assert_null(ll->meta->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
data = "{\"@a:ll1\" : [{\"a:hint\" : 1, \"x:xxx\" : { \"value\" : \"/x:no/x:yes\" }, "
"\"a:hint\" : 10},null,{\"a:hint\" : 3}], \"a:ll1\" : [1,2,3]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(ll->value, UINT8, "1", 1);
CHECK_LYD_META(ll->meta->next, 1, "hint", 1, 1, INT8, "1", 1);
CHECK_LYD_META(ll->meta->next->next, 1, "hint", 0, 1, INT8, "10", 10);
assert_non_null(tree->next);
CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next;
CHECK_LYD_VALUE(ll->value, UINT8, "2", 2);
assert_null(ll->meta);
assert_non_null(tree->next->next);
CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next->next;
CHECK_LYD_VALUE(ll->value, UINT8, "3", 3);
CHECK_LYD_META(ll->meta, 1, "hint", 0, 1, INT8, "3", 3);
assert_null(ll->meta->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:ll1\":[1,2,3],\"@a:ll1\":[{\"a:hint\":1,\"a:hint\":10},null,{\"a:hint\":3}]}");
lyd_free_all(tree);
/* missing referenced metadata node */
PARSER_CHECK_ERROR("{\"@a:ll1\":[{\"a:hint\":1}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Missing JSON data instance to be coupled with @a:ll1 metadata.", "/@a:ll1", 1);
PARSER_CHECK_ERROR("{\"a:ll1\":[1],\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Missing JSON data instance #2 of a:ll1 to be coupled with metadata.", "/a:ll1", 1);
PARSER_CHECK_ERROR("{\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2},{\"a:hint\":3}],\"a:ll1\" : [1, 2]}", 0, LYD_VALIDATE_PRESENT,
tree, LY_EVALID, "Missing JSON data instance #3 to be coupled with @a:ll1 metadata.", "/@a:ll1", 1);
}
static void
test_anydata(void **state)
{
const char *data;
struct lyd_node *tree;
data = "{\"a:any\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:any\":{}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:any\":{\"node\":20}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:any\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Expecting JSON name/object but anydata \"any\" is represented in input data as name/null.", NULL, 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}
static void
test_anyxml(void **state)
{
const char *data;
struct lyd_node *tree;
data = "{\"a:axml\":\"some-value in string\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":\"\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":55}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":false}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":null}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":[null,true,false]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":[null,true,{\"name\":[25,40, false]}]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* same as anydata tests */
data = "{\"a:axml\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":{}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_list(void **state)
{
const char *data;
struct lyd_node *tree, *iter;
struct lyd_node_inner *list;
struct lyd_node_term *leaf;
/* check hashes */
data = "{\"a:l1\":[{\"a\":\"one\",\"b\":\"one\",\"c\":1}]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1",
1, LYS_LIST, 0, 0, NULL, 0);
list = (struct lyd_node_inner *)tree;
LY_LIST_FOR(list->child, iter) {
assert_int_not_equal(0, iter->hash);
}
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* accept empty */
data = "{\"a:l1\":[]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
/* missing keys */
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"a\".", "/a:l1[b='b'][c='1']", 1);
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"a\" : \"a\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"b\".", "/a:l1[a='a']", 1);
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"b\" : \"b\", \"a\" : \"a\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"c\".", "/a:l1[a='a'][b='b']", 1);
/* key duplicate */
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\", \"a\" : \"a\", \"c\" : 1}]}", 0, LYD_VALIDATE_PRESENT,
tree, LY_EVALID, "Duplicate instance of \"c\".", "/a:l1[a='a'][b='b'][c='1'][c='1']/c", 1);
/* keys order, in contrast to XML, JSON accepts keys in any order even in strict mode */
CHECK_PARSE_LYD("{ \"a:l1\": [ {\"d\" : \"d\", \"a\" : \"a\", \"c\" : 1, \"b\" : \"b\"}]}", 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1",
1, LYS_LIST, 0, 0, NULL, 0);
list = (struct lyd_node_inner *)tree;
assert_non_null(leaf = (struct lyd_node_term *)list->child);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "b", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "c", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "d", 1, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LOG_CTX(NULL, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1,\"d\":\"d\"}]}");
lyd_free_all(tree);
CHECK_PARSE_LYD("{\"a:l1\":[{\"c\":1,\"b\":\"b\",\"a\":\"a\"}]}", LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1",
1, LYS_LIST, 0, 0, NULL, 0);
list = (struct lyd_node_inner *)tree;
assert_non_null(leaf = (struct lyd_node_term *)list->child);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a",
1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "b",
1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "c",
1, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LOG_CTX(NULL, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1}]}");
lyd_free_all(tree);
/* skip unknown nested nodes */
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":3,\"counters\":{\"count1\":\"c1\",\"count2\":\"c2\"}}]}";
CHECK_PARSE_LYD(data, LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":3}]}");
lyd_free_all(tree);
data = "{\"a:cp\":{\"@\":{\"a:hint\":1}}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
1, LYS_CONTAINER, 0, 0, NULL, 0);
CHECK_LYD_META(tree->meta, 1, "hint", 0, 1, INT8, "1", 1);
assert_null(tree->meta->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_container(void **state)
{
const char *data;
struct lyd_node *tree;
struct lyd_node_inner *cont;
CHECK_PARSE_LYD("{\"a:c\":{}}", 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c",
1, LYS_CONTAINER, 0, 0, NULL, 0);
cont = (struct lyd_node_inner *)tree;
assert_true(cont->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{}");
lyd_free_all(tree);
data = "{\"a:cp\":{}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
1, LYS_CONTAINER, 0, 0, NULL, 0);
cont = (struct lyd_node_inner *)tree;
assert_false(cont->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* skip container */
CHECK_PARSE_LYD("{\"a:unknown\":{\"a\":\"val\",\"b\":5}}", 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{}");
lyd_free_all(tree);
data = "{\"a:c\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Expecting JSON name/object but container \"c\" is represented in input data as name/null.", NULL, 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}
static void
test_opaq(void **state)
{
const char *data;
struct lyd_node *tree;
/* invalid value, no flags */
data = "{\"a:foo3\":[null]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-number-encoded uint32 value \"\".", "/a:foo3", 1);
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo3", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* special chars */
data = "{\"a:foo3\":\"ab\\\"\\\\\\r\\t\"}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* wrong encoding */
data = "{\"a:foo3\":\"25\"}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo3", 0, 0, NULL, 0, "25");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:foo4\":25}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo4", 0, 0, NULL, 0, "25");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* missing key, no flags */
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"d\":\"val_d\"}]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"c\".", "/a:l1[a='val_a'][b='val_b']", 1);
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* invalid key, no flags */
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-number-encoded int16 value \"val_c\".", "/a:l1[a='val_a'][b='val_b']/c", 1);
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":{\"val\":\"val_c\"}}]}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\"}]}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* invalid metadata */
data = "{\"@a:foo\":\"str\",\"@a:foo3\":1,\"a:foo3\":2}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Unknown module of node \"@a:foo\".", "/", 0);
CHECK_LOG_CTX("Missing JSON data instance to be coupled with @a:foo metadata.", "/@a:foo", 1);
/* empty name */
PARSER_CHECK_ERROR("{\"@a:foo\":{\"\":0}}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"JSON object member name cannot be a zero-length string.", "/@a:foo", 1);
/* opaque data tree format print */
data =
"{\n"
" \"ietf-netconf-nmda:get-data\": {\n"
" \"data\": {\n"
" \"ietf-keystore:keystore\": {\n"
" \"asymmetric-keys\": {\n"
" \"asymmetric-key\": [\n"
" {\n"
" \"name\": \"genkey\",\n"
" \"algorithm\": \"rsa2048\"\n"
" }\n"
" ]\n"
" }\n"
" },\n"
" \"ietf-netconf-server:netconf-server\": {\n"
" \"listen\": {\n"
" \"idle-timeout\": 3600,\n"
" \"endpoint\": [\n"
" {\n"
" \"name\": \"default-ssh\",\n"
" \"ssh\": {\n"
" \"tcp-server-parameters\": {\n"
" \"local-address\": \"0.0.0.0\",\n"
" \"local-port\": 830\n"
" },\n"
" \"ssh-server-parameters\": {\n"
" \"server-identity\": {\n"
" \"host-key\": [\n"
" {\n"
" \"name\": \"default-key\",\n"
" \"public-key\": {\n"
" \"keystore-reference\": \"genkey\"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" \"client-authentication\": {\n"
" \"supported-authentication-methods\": {\n"
" \"publickey\": [null],\n"
" \"passsword\": [null],\n"
" \"other\": [\n"
" \"interactive\",\n"
" \"gssapi\"\n"
" ]\n"
" }\n"
" }\n"
" }\n"
" }\n"
" }\n"
" ]\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_rpc(void **state)
{
const char *data;
char *str;
struct ly_in *in;
struct lyd_node *tree, *op;
const struct lyd_node *node;
const char *dsc = "Edit data in an NMDA datastore.\n"
"\n"
"If an error condition occurs such that an error severity\n"
"<rpc-error> element is generated, the server will stop\n"
"processing the <edit-data> operation and restore the\n"
"specified configuration to its complete state at\n"
"the start of this <edit-data> operation.";
assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-nmda", "2019-01-07", NULL)));
data = "{\"ietf-netconf-nmda:edit-data\":{"
"\"datastore\":\"ietf-datastores:running\","
"\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
"\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
"}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, &op));
ly_in_free(in, 0);
assert_non_null(op);
CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, dsc, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "edit-data", LYS_RPC,
0, 0, 0, 0, 0, NULL, 0);
node = tree;
CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "edit-data", LYS_RPC,
0, 0, 0, 0, 0, NULL, 0);
node = lyd_child(node)->next;
CHECK_LYSC_NODE(node->schema, "Inline config content.", 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config",
0, LYS_ANYDATA, 1, 0, NULL, 0);
node = ((struct lyd_node_any *)node)->value.tree;
CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
1, LYS_CONTAINER, 0, 0, NULL, 0);
node = lyd_child(node);
/* z has no value */
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_JSON, "z", 0, 0, NULL, 0, "");
node = node->parent->next;
/* l1 key c has invalid value so it is at the end */
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* append to parent */
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:r1", NULL, 0, &op));
assert_int_equal(LY_SUCCESS, ly_in_new_memory("{\"l1\": \"some str\", \"l2\": \"some other str\"}", &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, NULL));
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str, op, LYD_JSON, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK));
lyd_free_tree(op);
assert_string_equal(str, "{\"a:r1\":{\"l1\":\"some str\",\"l2\":\"some other str\"}}");
free(str);
}
static void
test_action(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *op;
data = "{\"a:c\":{\"act\":{\"al\":\"value\"}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, &op));
ly_in_free(in, 0);
assert_non_null(op);
CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "act", LYS_ACTION,
1, 0, 0, 1, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
/* TODO */
}
static void
test_notification(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *ntf;
data = "{\"a:c\":{\"n1\":{\"nl\":\"value\"}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_YANG, &tree, &ntf));
ly_in_free(in, 0);
assert_non_null(ntf);
CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:n2\":{}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_YANG, &tree, &ntf));
ly_in_free(in, 0);
assert_non_null(ntf);
CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 0, NULL, 0, 0x4, 1, 0, "n2", 0, 0, NULL, 0);
assert_non_null(tree);
assert_ptr_equal(ntf, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
/* TODO */
}
static void
test_reply(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *op;
const struct lyd_node *node;
data = "{\"a:c\":{\"act\":{\"al\":25}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_REPLY_YANG, &tree, &op));
ly_in_free(in, 0);
assert_non_null(op);
CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "act", LYS_ACTION,
1, 0, 0, 1, 0, NULL, 0);
node = lyd_child(op);
CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_STATUS_CURR | LYS_IS_OUTPUT, 1, "al", 0, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
/* TODO print only rpc-reply node and then output subtree */
CHECK_LYD_STRING(lyd_child(op), LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:al\":25}");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:c\":{\"act\":{\"al\":25}}}");
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
/* TODO */
}
static void
test_restconf_rpc(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *envp;
assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-nmda", "2019-01-07", NULL)));
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/ietf-netconf-nmda:edit-data", NULL, 0, &tree));
data = "{\"ietf-netconf-nmda:input\":{"
"\"datastore\":\"ietf-datastores:running\","
"\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
"\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
"}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, tree, in, LYD_JSON, LYD_TYPE_RPC_RESTCONF, &envp, NULL));
ly_in_free(in, 0);
/* the same just connected to the edit-data RPC */
data = "{\"ietf-netconf-nmda:edit-data\":{"
"\"datastore\":\"ietf-datastores:running\","
"\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
"\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
"}}";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
lyd_free_all(envp);
}
static void
test_restconf_notification(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *ntf;
data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\",\"a:c\":{\"n1\":{\"nl\":\"value\"}}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf));
ly_in_free(in, 0);
/* envelopes separately */
data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\"}}";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
/* notification with the parent node */
data = "{\"a:c\":{\"n1\":{\"nl\":\"value\"}}}";
CHECK_LYD_STRING(lyd_parent(ntf), LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
lyd_free_all(ntf);
/* wrong order */
data = "{\"ietf-restconf:notification\":{\"a:n2\":{},\"eventTime\":\"2013-12-21T00:01:00Z\"}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf));
ly_in_free(in, 0);
lyd_free_all(tree);
lyd_free_all(ntf);
/* unknown notification */
data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\",\"invalid:n2\":{}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf));
UTEST_LOG_CTX_CLEAN;
ly_in_free(in, 0);
lyd_free_all(tree);
}
static void
test_restconf_reply(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *envp;
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:c/act", NULL, 0, &tree));
data = "{\"a:output\":{\"al\":25}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child(tree), in, LYD_JSON, LYD_TYPE_REPLY_RESTCONF, &envp, NULL));
ly_in_free(in, 0);
/* connected to the RPC with the parent */
data = "{\"a:c\":{\"act\":{\"al\":25}}}";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
lyd_free_all(envp);
}
static void
test_metadata(void **state)
{
const char *data;
struct lyd_node *tree;
/* invalid metadata value */
data = "{\"a:c\":{\"x\":\"xval\",\"@x\":{\"a:hint\":\"value\"}}}";
assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
assert_null(tree);
CHECK_LOG_CTX("Invalid non-number-encoded int8 value \"value\".", "/a:c/x/@a:hint", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_leaf, setup),
UTEST(test_leaflist, setup),
UTEST(test_anydata, setup),
UTEST(test_anyxml, setup),
UTEST(test_list, setup),
UTEST(test_container, setup),
UTEST(test_opaq, setup),
UTEST(test_rpc, setup),
UTEST(test_action, setup),
UTEST(test_notification, setup),
UTEST(test_reply, setup),
UTEST(test_restconf_rpc, setup),
UTEST(test_restconf_notification, setup),
UTEST(test_restconf_reply, setup),
UTEST(test_metadata, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
/**
* @file test_printer_json.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from printer_yang.c
*
* Copyright (c) 2019-2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _UTEST_MAIN_
#include "utests.h"
static int
setup(void **state)
{
const char *schema1 = "module schema1 {namespace urn:tests:schema1;prefix schema1;yang-version 1.1;"
"revision 2014-05-08;"
"anydata data;"
"}";
const char *schema2 = "module schema2 {namespace urn:tests:schema2;prefix s2;yang-version 1.1;"
" container a {"
" container b {"
" leaf c {"
" type string;"
" default \"dflt\";"
" }"
" }"
" }"
"}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema1, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
return 0;
}
static void
test_container_presence(void **state)
{
struct lyd_node *tree;
char *buffer = NULL;
const char *data = "{\"schema1:data\":{\"cont1\":{}}}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, tree, LYD_JSON, LYD_PRINT_SHRINK));
CHECK_STRING(buffer, data);
free(buffer);
lyd_free_all(tree);
}
static void
test_empty_container_wd_trim(void **state)
{
struct lyd_node *tree;
char *buffer = NULL;
const char *data = "{\"schema2:a\":{\"b\":{\"c\":\"dflt\"}}}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WD_TRIM));
CHECK_STRING(buffer, "{}");
free(buffer);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WD_TRIM | LYD_PRINT_KEEPEMPTYCONT));
CHECK_STRING(buffer, "{\"schema2:a\":{\"b\":{}}}");
free(buffer);
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_container_presence, setup),
UTEST(test_empty_container_wd_trim, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,344 @@
/*
* @file test_printer_xml.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from printer_yang.c
*
* Copyright (c) 2019-2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _UTEST_MAIN_
#include "utests.h"
#include <string.h>
#include "context.h"
#include "out.h"
#include "parser_data.h"
#include "printer_data.h"
#include "tests_config.h"
#include "tree_schema.h"
static int
setup(void **state)
{
const char *schema_defs = "module defs {namespace urn:tests:defs;prefix d;yang-version 1.1;"
"identity crypto-alg; identity interface-type; identity ethernet {base interface-type;} identity fast-ethernet {base ethernet;}}";
const char *schema_types = "module types {namespace urn:tests:types;prefix t;yang-version 1.1; import defs {prefix defs;}"
"feature f; identity gigabit-ethernet { base defs:ethernet;}"
"container cont {leaf leaftarget {type empty;}"
" list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
" action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
" leaf-list leaflisttarget {type uint8; max-elements 5;}}"
"list list {key id; leaf id {type string;} leaf value {type string;} leaf-list targets {type string;}}"
"list list2 {key \"id value\"; leaf id {type string;} leaf value {type string;}}"
"list list_inst {key id; leaf id {type instance-identifier {require-instance true;}} leaf value {type string;}}"
"list list_ident {key id; leaf id {type identityref {base defs:interface-type;}} leaf value {type string;}}"
"leaf-list leaflisttarget {type string;}"
"leaf binary {type binary {length 5 {error-message \"This base64 value must be of length 5.\";}}}"
"leaf binary-norestr {type binary;}"
"leaf int8 {type int8 {range 10..20;}}"
"leaf uint8 {type uint8 {range 150..200;}}"
"leaf int16 {type int16 {range -20..-10;}}"
"leaf uint16 {type uint16 {range 150..200;}}"
"leaf int32 {type int32;}"
"leaf uint32 {type uint32;}"
"leaf int64 {type int64;}"
"leaf uint64 {type uint64;}"
"leaf bits {type bits {bit zero; bit one {if-feature f;} bit two;}}"
"leaf enums {type enumeration {enum white; enum yellow {if-feature f;}}}"
"leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
"leaf dec64-norestr {type decimal64 {fraction-digits 18;}}"
"leaf str {type string {length 8..10; pattern '[a-z ]*';}}"
"leaf str-norestr {type string;}"
"leaf bool {type boolean;}"
"leaf empty {type empty;}"
"leaf ident {type identityref {base defs:interface-type;}}"
"leaf inst {type instance-identifier {require-instance true;}}"
"leaf inst-noreq {type instance-identifier {require-instance false;}}"
"leaf lref {type leafref {path /leaflisttarget; require-instance true;}}"
"leaf lref2 {type leafref {path \"../list[id = current()/../str-norestr]/targets\"; require-instance true;}}"
"leaf un1 {type union {"
" type leafref {path /int8; require-instance true;}"
" type union { type identityref {base defs:interface-type;} type instance-identifier {require-instance true;} }"
" type string {length 1..20;}}}"
"anydata any;"
"rpc sum {input {leaf x {type uint8;} leaf y {type uint8;}} output {leaf result {type uint16;}}}}";
const char *schema_defaults =
"module defaults {\n"
" namespace \"urn:defaults\";\n"
" prefix d;\n"
" leaf a {\n"
" type union {\n"
" type instance-identifier;\n"
" type string;\n"
" }\n"
" default \"/d:b\";\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" }\n"
"}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema_defs, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema_types, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema_defaults, LYS_IN_YANG, NULL, NULL);
return 0;
}
#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, PRINT_OPTION)
static void
test_anydata(void **state)
{
struct lyd_node *tree;
const char *data;
data = "<any xmlns=\"urn:tests:types\"><somexml xmlns:x=\"url:x\" xmlns=\"example.com\"><x:x/></somexml></any>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
/* canonized */
data = "<any xmlns=\"urn:tests:types\"><somexml xmlns=\"example.com\"><x xmlns=\"url:x\"/></somexml></any>";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\"/>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <cont>\n"
" <defs:elem1 xmlns:defs=\"urn:tests:defs\">\n"
" <elem2 xmlns:defaults=\"urn:defaults\" defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
" </elem2>\n"
" </defs:elem1>\n"
" </cont>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
/* cont should be normally parsed */
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "any", 0, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_NODE_ANY((struct lyd_node_any *)tree, 0, 0, 0, LYD_ANYDATA_DATATREE);
struct lyd_node *tree_tmp = ((struct lyd_node_any *)tree)->value.tree;
CHECK_LYSC_NODE(tree_tmp->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "cont", 1, LYS_CONTAINER, 0, 0, NULL, 0);
/* but its children not */
assert_null(((struct lyd_node_inner *)tree_tmp)->child->schema);
/* canonized */
data =
"<any xmlns=\"urn:tests:types\">\n"
" <cont>\n"
" <elem1 xmlns=\"urn:tests:defs\">\n"
" <elem2 xmlns=\"urn:tests:types\" xmlns:defs=\"urn:tests:defs\" xmlns:defaults=\"urn:defaults\" "
"defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
" </elem2>\n"
" </elem1>\n"
" </cont>\n"
"</any>\n";
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <ahoj attr=\"&lt;test\">\n"
" ahoj jak se vede &lt; how are you"
" </ahoj>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <leaflisttarget> ahoj </leaflisttarget>\n"
" <leaflisttarget> nazdar </leaflisttarget>\n"
" <leaflisttarget> Čau </leaflisttarget>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <cont2/>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <cont>\n"
" &lt; how are you"
" </cont>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_defaults(void **state)
{
struct lyd_node *tree;
const char *data;
const char *data_trim;
const char *data_all;
const char *data_all_tag;
const char *data_impl_tag;
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));
/* standard default value */
data = "<c xmlns=\"urn:defaults\">aa</c>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
" ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
"<c xmlns=\"urn:defaults\">aa</c>";
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
" ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
"<c xmlns=\"urn:defaults\">aa</c>";
CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* string value equal to the default but default is an unresolved instance-identifier, so they are not considered equal */
data = "<a xmlns=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* instance-identifier value equal to the default, should be considered equal */
data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
data_trim = "<b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
data_all = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
data_all_tag = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
" ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
"<b xmlns=\"urn:defaults\">val</b>"
"<c xmlns=\"urn:defaults\">aa</c>";
data_impl_tag = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_trim);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all_tag);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_impl_tag);
lyd_free_all(tree);
}
#if 0
static void
test_rpc(void **state)
{
struct state_s *s = (struct state_s *)(*state);
struct lyd_node *tree1;
struct lyd_node *tree2;
const struct lyd_node **trees;
const char *request;
const char *reply, *result;
char *printed;
ssize_t len;
struct ly_out *out;
s->func = test_rpc;
assert_non_null(out = ly_out_new_memory(&printed, 0));
request = "<sum xmlns=\"urn:tests:types\"><x>10</x><y>20</y></sum>";
reply = "<result xmlns=\"urn:tests:types\">30</result>";
result = "<sum xmlns=\"urn:tests:types\"><result>30</result></sum>";
assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, request);
ly_out_reset(out);
assert_non_null(trees = lyd_trees_new(1, tree1));
assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, result);
ly_out_reset(out);
lyd_trees_free(trees, 0);
lyd_free_all(tree1);
lyd_free_all(tree2);
/* no arguments */
request = "<sum xmlns=\"urn:tests:types\"/>";
reply = "";
result = "<sum xmlns=\"urn:tests:types\"/>";
assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, request);
ly_out_reset(out);
assert_non_null(trees = lyd_trees_new(1, tree1));
assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, result);
ly_out_reset(out);
lyd_trees_free(trees, 0);
lyd_free_all(tree1);
lyd_free_all(tree2);
/* action
* "container cont {leaf leaftarget {type empty;}"
"list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
"action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
"leaf-list leaflisttarget {type uint8; max-elements 5;}}"
*/
request = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><a>test</a></test></listtarget></cont>";
reply = "<b xmlns=\"urn:tests:types\">test-reply</b>";
result = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><b>test-reply</b></test></listtarget></cont>";
assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, request);
ly_out_reset(out);
assert_non_null(trees = lyd_trees_new(1, tree1));
assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, result);
ly_out_reset(out);
lyd_trees_free(trees, 0);
lyd_free_all(tree1);
lyd_free_all(tree2);
ly_out_free(out, NULL, 1);
s->func = NULL;
}
#endif
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_anydata, setup),
UTEST(test_defaults, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,822 @@
/**
* @file test_tree_data.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from tree_data.c
*
* Copyright (c) 2018-2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _UTEST_MAIN_
#include "utests.h"
#include "libyang.h"
#include "ly_common.h"
#include "path.h"
#include "xpath.h"
static int
setup(void **state)
{
const char *schema1 = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;"
"revision 2014-05-08;"
"leaf bar {type string;}"
"list l1 { key \"a b\"; leaf a {type string;} leaf b {type string;} leaf c {type string;}}"
"leaf foo { type string;}"
"leaf-list ll { type string;}"
"container c {leaf-list x {type string;}}"
"anydata any {config false;}"
"list l2 {config false;"
" container c{leaf x {type string;} leaf-list d {type string;}}"
"}}";
const char *schema2 = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}}"
"anydata any {config false;}"
"}";
const char *schema3 = "module c {yang-version 1.1; namespace \"http://example.com/main\";prefix m;"
"import \"ietf-inet-types\" {prefix inet;}"
"typedef optional-ip-address {type union {"
" type inet:ip-address;"
" type string;"
"}}"
"container cont {"
" list nexthop {min-elements 1; key \"gateway\";"
" leaf gateway {type optional-ip-address;}"
" }"
" leaf-list pref {type inet:ipv6-prefix;}"
"}}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema1, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema3, LYS_IN_YANG, NULL, NULL);
return 0;
}
#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
#define CHECK_PARSE_LYD_PARAM_CTX(CTX, INPUT, PARSE_OPTION, OUT_NODE) \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(CTX, INPUT, LYD_XML, PARSE_OPTION, LYD_VALIDATE_PRESENT, &OUT_NODE)); \
assert_non_null(OUT_NODE);
#define RECREATE_CTX_WITH_MODULE(CTX, MODULE) \
ly_ctx_destroy(CTX); \
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &CTX)); \
assert_int_equal(LY_SUCCESS, ly_in_new_memory(MODULE, &_UC->in)); \
assert_int_equal(LY_SUCCESS, lys_parse(CTX, _UC->in, LYS_IN_YANG, NULL, NULL)); \
ly_in_free(_UC->in, 0);
static void
test_compare(void **state)
{
struct lyd_node *tree1, *tree2;
const char *data1;
const char *data2;
assert_int_equal(LY_SUCCESS, lyd_compare_single(NULL, NULL, 0));
data1 = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
data2 = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>y</c></l1>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
assert_int_equal(LY_ENOT, lyd_compare_single(((struct lyd_node_inner *)tree1)->child, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1->next, tree2->next, LYD_COMPARE_FULL_RECURSION));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next->next, tree2->next, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<ll xmlns=\"urn:tests:a\">a</ll><ll xmlns=\"urn:tests:a\">b</ll>";
data2 = "<ll xmlns=\"urn:tests:a\">b</ll>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(NULL, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, NULL, 0));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<c xmlns=\"urn:tests:a\"><x>x</x></c>";
data2 = "<c xmlns=\"urn:tests:a\"><x>y</x></c>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<c xmlns=\"urn:tests:a\"><x>x</x></c>";
data2 = "<c xmlns=\"urn:tests:a\"><x>x</x><x>y</x></c>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<any xmlns=\"urn:tests:a\"><x>x</x></any>";
data2 = "<any xmlns=\"urn:tests:a\"><x>x</x><x>y</x></any>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1->next, tree2->next, 0));
lyd_free_all(tree1);
data1 = "<any xmlns=\"urn:tests:a\"><x>x</x><x>y</x></any>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<c xmlns=\"urn:tests:a\"><x>c</x><x>a</x><x>b</x></c>";
data2 = "<c xmlns=\"urn:tests:a\"><x>a</x><x>b</x><x>c</x></c>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
}
static void
test_compare_diff_ctx(void **state)
{
struct lyd_node *tree1, *tree2;
const char *data1, *data2;
struct ly_ctx *ctx2 = NULL;
const char *module;
/* create second context with the same schema */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has a different name */
module = "module c {namespace urn:tests:c;prefix c;yang-version 1.1;"
"revision 2014-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:c\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has a different revision */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2015-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has no revision */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has a different parent nodetype */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"container l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(lyd_child(lyd_child(tree1)), lyd_child(lyd_child(tree2)), 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with the same opaq data nodes */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"anydata any {config false;}"
"}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>bb:x</x></any>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with the different opaq data node value */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"anydata any {config false;}"
"}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>bb:y</x></any>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with the wrong prefix in opaq data node value */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"anydata any {config false;}"
"}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>cc:x</x></any>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* clean up */
ly_ctx_destroy(ctx2);
_UC->in = NULL;
}
static void
test_dup(void **state)
{
struct lyd_node *tree1, *tree2;
const char *result;
const char *data;
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, LYD_DUP_RECURSIVE, &tree2));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
result = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b></l1>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, 0, &tree2));
lyd_free_all(tree1);
CHECK_PARSE_LYD(result, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
result = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_siblings(tree1, NULL, LYD_DUP_RECURSIVE, &tree2));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2->next, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree2);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, LYD_DUP_RECURSIVE, &tree2));
lyd_free_all(tree1);
CHECK_PARSE_LYD(result, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree2);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, 0, &tree2));
lyd_free_all(tree1);
result = "<l2 xmlns=\"urn:tests:a\"/>";
CHECK_PARSE_LYD_PARAM(result, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<any xmlns=\"urn:tests:a\"><c><a>a</a></c></any>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, 0, &tree2));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), NULL, LYD_DUP_WITH_PARENTS, &tree2));
int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM;
CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "x", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, (struct lyd_node *)tree2->parent->parent,
LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>c</c></l1>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(((struct lyd_node_inner *)tree1)->child->prev, NULL,
LYD_DUP_WITH_PARENTS, &tree2));
flag = LYS_CONFIG_W | LYS_SET_ENUM;
CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "c", 0, LYS_LEAF, 1, 0, NULL, 0);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, (struct lyd_node *)tree2->parent, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, 0, &tree2));
assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), (struct lyd_node_inner *)tree2,
LYD_DUP_WITH_PARENTS, NULL));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* invalid */
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>c</c></l1><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_EINVAL, lyd_dup_single(((struct lyd_node_inner *)tree1)->child->prev,
(struct lyd_node_inner *)tree1->next, LYD_DUP_WITH_PARENTS, NULL));
CHECK_LOG_CTX("None of the duplicated node \"c\" schema parents match the provided parent \"c\".", NULL, 0);
lyd_free_all(tree1);
}
static void
test_target(void **state)
{
const struct lyd_node_term *term;
struct lyd_node *tree;
struct lyxp_expr *exp;
struct ly_path *path;
const char *path_str = "/a:l2[2]/c/d[3]";
const char *data =
"<l2 xmlns=\"urn:tests:a\"><c>"
" <d>a</d>"
" </c></l2>"
"<l2 xmlns=\"urn:tests:a\"><c>"
" <d>a</d>"
" <d>b</d>"
" <d>b</d>"
" <d>c</d>"
"</c></l2>"
"<l2 xmlns=\"urn:tests:a\"><c>"
"</c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path_str, strlen(path_str), 0, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp));
assert_int_equal(LY_SUCCESS, ly_path_compile(UTEST_LYCTX, NULL, NULL, NULL, exp, LY_PATH_OPER_INPUT,
LY_PATH_TARGET_SINGLE, 1, LY_VALUE_JSON, NULL, &path));
assert_int_equal(LY_SUCCESS, lyd_find_target(path, tree, (struct lyd_node **)&term));
const int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM | LYS_ORDBY_USER;
CHECK_LYSC_NODE(term->schema, NULL, 0, flag, 1, "d", 0, LYS_LEAFLIST, 1, 0, NULL, 0);
assert_string_equal(lyd_get_value(&term->node), "b");
assert_string_equal(lyd_get_value(term->prev), "b");
lyd_free_all(tree);
ly_path_free(UTEST_LYCTX, path);
lyxp_expr_free(UTEST_LYCTX, exp);
}
static void
test_list_pos(void **state)
{
const char *data;
struct lyd_node *tree;
data = "<bar xmlns=\"urn:tests:a\">test</bar>"
"<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b></l1>"
"<l1 xmlns=\"urn:tests:a\"><a>two</a><b>two</b></l1>"
"<foo xmlns=\"urn:tests:a\">test</foo>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_int_equal(0, lyd_list_pos(tree));
assert_int_equal(1, lyd_list_pos(tree->next));
assert_int_equal(2, lyd_list_pos(tree->next->next));
assert_int_equal(0, lyd_list_pos(tree->next->next->next));
lyd_free_all(tree);
data = "<ll xmlns=\"urn:tests:a\">one</ll>"
"<ll xmlns=\"urn:tests:a\">two</ll>"
"<ll xmlns=\"urn:tests:a\">three</ll>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_int_equal(1, lyd_list_pos(tree));
assert_int_equal(2, lyd_list_pos(tree->next));
assert_int_equal(3, lyd_list_pos(tree->next->next));
lyd_free_all(tree);
data = "<ll xmlns=\"urn:tests:a\">one</ll>"
"<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b></l1>"
"<ll xmlns=\"urn:tests:a\">two</ll>"
"<l1 xmlns=\"urn:tests:a\"><a>two</a><b>two</b></l1>"
"<ll xmlns=\"urn:tests:a\">three</ll>"
"<l1 xmlns=\"urn:tests:a\"><a>three</a><b>three</b></l1>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_string_equal("l1", tree->schema->name);
assert_int_equal(1, lyd_list_pos(tree));
assert_int_equal(2, lyd_list_pos(tree->next));
assert_int_equal(3, lyd_list_pos(tree->next->next));
assert_string_equal("ll", tree->next->next->next->schema->name);
assert_int_equal(1, lyd_list_pos(tree->next->next->next));
assert_int_equal(2, lyd_list_pos(tree->next->next->next->next));
assert_int_equal(3, lyd_list_pos(tree->next->next->next->next->next));
lyd_free_all(tree);
}
static void
test_first_sibling(void **state)
{
const char *data;
struct lyd_node *tree;
struct lyd_node_inner *parent;
data = "<bar xmlns=\"urn:tests:a\">test</bar>"
"<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b><c>one</c></l1>"
"<foo xmlns=\"urn:tests:a\">test</foo>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_ptr_equal(tree, lyd_first_sibling(tree->next));
assert_ptr_equal(tree, lyd_first_sibling(tree));
assert_ptr_equal(tree, lyd_first_sibling(tree->prev));
parent = (struct lyd_node_inner *)tree->next;
assert_int_equal(LYS_LIST, parent->schema->nodetype);
assert_ptr_equal(parent->child, lyd_first_sibling(parent->child->next));
assert_ptr_equal(parent->child, lyd_first_sibling(parent->child));
assert_ptr_equal(parent->child, lyd_first_sibling(parent->child->prev));
lyd_free_all(tree);
}
static void
test_find_path(void **state)
{
struct lyd_node *root;
const struct lys_module *mod;
mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "c");
assert_non_null(mod);
assert_int_equal(LY_SUCCESS, lyd_new_inner(NULL, mod, "cont", 0, &root));
assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/nexthop[gateway='10.0.0.1']", NULL, LYD_NEW_PATH_UPDATE, NULL));
assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/nexthop[gateway='2100::1']", NULL, LYD_NEW_PATH_UPDATE, NULL));
assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/pref[.='fc00::/64']", NULL, 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/nexthop[gateway='10.0.0.1']", 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/nexthop[gateway='2100::1']", 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/pref[.='fc00::/64']", 0, NULL));
assert_int_equal(LY_EVALID, lyd_find_path(root, "/cont", 0, NULL));
CHECK_LOG_CTX("Prefix missing for \"cont\" in path.", "/c:cont", 0);
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "nexthop[gateway='2100::1']", 0, NULL));
lyd_free_all(root);
}
static void
test_data_hash(void **state)
{
struct lyd_node *tree;
const char *schema, *data;
schema =
"module test-data-hash {"
" yang-version 1.1;"
" namespace \"urn:tests:tdh\";"
" prefix t;"
" container c {"
" leaf-list ll {"
" type string;"
" }"
" }"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* The number of <ll/> must be greater or equal to LYD_HT_MIN_ITEMS
* for the correct test run. It should guarantee the creation of a hash table.
*/
assert_true(LYD_HT_MIN_ITEMS <= 4);
data =
"<c xmlns='urn:tests:tdh'>"
" <ll/>"
" <ll/>"
" <ll/>"
" <ll/>"
"</c>";
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX("Duplicate instance of \"ll\".", "/test-data-hash:c/ll[.='']", 1);
lyd_free_all(tree);
}
static void
test_lyxp_vars(void **UNUSED(state))
{
struct lyxp_var *vars;
/* Test free. */
vars = NULL;
lyxp_vars_free(vars);
/* Bad arguments for lyxp_vars_add(). */
assert_int_equal(LY_EINVAL, lyxp_vars_set(NULL, "var1", "val1"));
assert_int_equal(LY_EINVAL, lyxp_vars_set(&vars, NULL, "val1"));
assert_int_equal(LY_EINVAL, lyxp_vars_set(&vars, "var1", NULL));
lyxp_vars_free(vars);
vars = NULL;
/* Add one item. */
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
assert_int_equal(LY_ARRAY_COUNT(vars), 1);
assert_string_equal(vars[0].name, "var1");
assert_string_equal(vars[0].value, "val1");
lyxp_vars_free(vars);
vars = NULL;
/* Add three items. */
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var2", "val2"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var3", "val3"));
assert_int_equal(LY_ARRAY_COUNT(vars), 3);
assert_string_equal(vars[0].name, "var1");
assert_string_equal(vars[0].value, "val1");
assert_string_equal(vars[1].name, "var2");
assert_string_equal(vars[1].value, "val2");
assert_string_equal(vars[2].name, "var3");
assert_string_equal(vars[2].value, "val3");
lyxp_vars_free(vars);
vars = NULL;
/* Change value of a variable. */
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var2", "val2"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "new_value"));
assert_string_equal(vars[0].name, "var1");
assert_string_equal(vars[0].value, "new_value");
assert_string_equal(vars[1].name, "var2");
assert_string_equal(vars[1].value, "val2");
lyxp_vars_free(vars);
vars = NULL;
}
static void
test_data_leafref_nodes(void **state)
{
struct lyd_node *tree, *iter;
struct lyd_node_term *target_node = NULL, *leafref_node;
const struct lyd_leafref_links_rec *rec;
const char *schema, *data, *value;
ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING);
schema =
"module test-data-hash {"
" yang-version 1.1;"
" namespace \"urn:tests:tdh\";"
" prefix t;"
" leaf-list ll {"
" type string;"
" }"
" container c1 {"
" leaf ref1 {"
" type leafref {"
" path \"../../ll\";"
" }"
" }"
" }"
" leaf ref2 {"
" type leafref {"
" path \"../ll\";"
" }"
" }"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data =
"{"
" \"test-data-hash:ll\": [\"qwe\", \"asd\"],"
" \"test-data-hash:c1\": { \"ref1\": \"qwe\"},"
" \"test-data-hash:ref2\": \"asd\""
"}";
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ll") == 0) {
value = lyd_get_value(iter);
if (strcmp(value, "asd") == 0) {
target_node = (struct lyd_node_term *)iter;
}
}
if (strcmp(iter->schema->name, "ref2") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
}
/* verify state after leafref plugin validation */
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of target */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "ASD"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
/* change back to original value */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "asd"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of leafref */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "asd"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* freeing whole tree */
lyd_free_all(tree);
}
static void
test_data_leafref_nodes2(void **state)
{
struct lyd_node *tree, *iter;
const char *schema, *data;
struct lyd_node_term *leafref_node = NULL;
const struct lyd_node_term *target_node1, *target_node2;
const struct lyd_leafref_links_rec *rec;
ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING);
schema =
"module test-data-hash {"
" yang-version 1.1;"
" namespace \"urn:tests:tdh\";"
" prefix t;"
" list l1 {"
" key \"l1 l2\";"
" leaf l1 {"
" type string;"
" }"
" leaf l2 {"
" type string;"
" }"
" }"
" leaf ref1 {"
" type leafref {"
" path \"../l1/l1\";"
" }"
" }"
" leaf-list ll1 {"
" type string;"
" config false;"
" }"
" leaf ref2 {"
" type leafref {"
" path \"../ll1\";"
" }"
" config false;"
" }"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data =
"{"
" \"test-data-hash:l1\": ["
" {\"l1\": \"A\", \"l2\": \"B\"},"
" {\"l1\": \"A\", \"l2\": \"C\"}"
" ],"
" \"test-data-hash:ref1\": \"A\","
" \"test-data-hash:ll1\": [\"asd\", \"qwe\", \"asd\"],"
" \"test-data-hash:ref2\": \"asd\""
"}";
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ref1") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
}
/* verify state after leafref plugin validation */
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
target_node1 = rec->target_nodes[0];
target_node2 = rec->target_nodes[1];
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* value modification of leafref to remove all links*/
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node2, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "A"));
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* verify duplicated value in leaf-list */
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ref2") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
}
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
target_node1 = rec->target_nodes[0];
target_node2 = rec->target_nodes[1];
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* freeing whole tree */
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_compare, setup),
UTEST(test_compare_diff_ctx, setup),
UTEST(test_dup, setup),
UTEST(test_target, setup),
UTEST(test_list_pos, setup),
UTEST(test_first_sibling, setup),
UTEST(test_find_path, setup),
UTEST(test_data_hash, setup),
UTEST(test_lyxp_vars),
UTEST(test_data_leafref_nodes),
UTEST(test_data_leafref_nodes2),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff