summaryrefslogtreecommitdiffstats
path: root/tests/utests/extensions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 04:20:26 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 04:20:26 +0000
commit044203039cebe3c05161f8f104a039d4744ca6d0 (patch)
tree1073c2308492e6aea4c66cb7436ee92db2abfd42 /tests/utests/extensions
parentInitial commit. (diff)
downloadlibyang2-044203039cebe3c05161f8f104a039d4744ca6d0.tar.xz
libyang2-044203039cebe3c05161f8f104a039d4744ca6d0.zip
Adding upstream version 2.1.30.upstream/2.1.30
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/utests/extensions')
-rw-r--r--tests/utests/extensions/test_metadata.c211
-rw-r--r--tests/utests/extensions/test_nacm.c124
-rw-r--r--tests/utests/extensions/test_schema_mount.c1566
-rw-r--r--tests/utests/extensions/test_structure.c255
-rw-r--r--tests/utests/extensions/test_yangdata.c273
5 files changed, 2429 insertions, 0 deletions
diff --git a/tests/utests/extensions/test_metadata.c b/tests/utests/extensions/test_metadata.c
new file mode 100644
index 0000000..39d29be
--- /dev/null
+++ b/tests/utests/extensions/test_metadata.c
@@ -0,0 +1,211 @@
+/**
+ * @file test_metadata.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for Metadata extension (annotation) support
+ *
+ * Copyright (c) 2019 - 2022 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 "plugins_exts.h"
+#include "plugins_exts/metadata.h"
+
+static void
+test_yang(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ const char *units;
+
+ const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:metadata:a; prefix a;"
+ "import ietf-yang-metadata {prefix md;}"
+ "feature f;"
+ "md:annotation x {"
+ " description \"test\";"
+ " if-feature f;"
+ " reference \"test\";"
+ " status \"current\";"
+ " type uint8;"
+ " units meters;"
+ "}}";
+ const char *feats[] = {"f", NULL};
+
+ UTEST_ADD_MODULE(data, LYS_IN_YANG, feats, &mod);
+ assert_int_equal(1, LY_ARRAY_COUNT(mod->compiled->exts));
+ e = &mod->compiled->exts[0];
+ assert_non_null(e->compiled);
+ assert_non_null(e->substmts);
+ lyplg_ext_get_storage(e, LY_STMT_UNITS, sizeof units, (const void **)&units);
+ assert_string_equal("meters", units);
+
+ /* invalid */
+ /* missing mandatory type substatement */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
+ "import ietf-yang-metadata {prefix md;}"
+ "md:annotation aa;}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Missing mandatory keyword \"type\" as a child of \"md:annotation aa\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* not allowed substatement */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
+ "import ietf-yang-metadata {prefix md;}"
+ "md:annotation aa {default x;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid keyword \"default\" as a child of \"md:annotation aa\" extension instance.",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* invalid cardinality of units substatement */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
+ "import ietf-yang-metadata {prefix md;}"
+ "md:annotation aa {type string; units x; units y;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Duplicate keyword \"units\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* invalid cardinality of status substatement */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
+ "import ietf-yang-metadata {prefix md;}"
+ "md:annotation aa {type string; status current; status obsolete;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Duplicate keyword \"status\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* invalid cardinality of status substatement */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
+ "import ietf-yang-metadata {prefix md;}"
+ "md:annotation aa {type string; type uint8;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Duplicate keyword \"type\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* duplication of the same annotation */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
+ "import ietf-yang-metadata {prefix md;}"
+ "md:annotation aa {type string;} md:annotation aa {type uint8;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Extension md:annotation is instantiated multiple times.",
+ "/aa:{extension='md:annotation'}/aa");
+}
+
+static void
+test_yin(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ const char *data, *units;
+
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"a\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:a\"/><prefix value=\"a\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<feature name=\"f\"/>\n"
+ "<md:annotation name=\"x\">\n"
+ " <description><text>test</text></description>\n"
+ " <reference><text>test</text></reference>\n"
+ " <if-feature name=\"f\"/>\n"
+ " <status value=\"current\"/>\n"
+ " <type name=\"uint8\"/>\n"
+ " <units name=\"meters\"/>\n"
+ "</md:annotation></module>";
+ const char *feats[] = {"f", NULL};
+
+ UTEST_ADD_MODULE(data, LYS_IN_YIN, feats, &mod);
+ assert_int_equal(1, LY_ARRAY_COUNT(mod->compiled->exts));
+ e = &mod->compiled->exts[0];
+ assert_non_null(e->compiled);
+ assert_non_null(e->substmts);
+ lyplg_ext_get_storage(e, LY_STMT_UNITS, sizeof units, (const void **)&units);
+ assert_string_equal("meters", units);
+
+ /* invalid */
+ /* missing mandatory type substatement */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<md:annotation name=\"aa\"/>\n"
+ "</module>";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Missing mandatory keyword \"type\" as a child of \"md:annotation aa\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* not allowed substatement */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<md:annotation name=\"aa\">\n"
+ " <default value=\"x\"/>\n"
+ "</md:annotation></module>";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Invalid keyword \"default\" as a child of \"md:annotation aa\" extension instance.",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* invalid cardinality of units substatement */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<md:annotation name=\"aa\">\n"
+ " <type name=\"string\"/>\n"
+ " <units name=\"x\"/>\n"
+ " <units name=\"y\"/>\n"
+ "</md:annotation></module>";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Duplicate keyword \"units\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* invalid cardinality of status substatement */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<md:annotation name=\"aa\">\n"
+ " <type name=\"string\"/>\n"
+ " <status value=\"current\"/>\n"
+ " <status value=\"obsolete\"/>\n"
+ "</md:annotation></module>";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Duplicate keyword \"status\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* invalid cardinality of status substatement */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<md:annotation name=\"aa\">\n"
+ " <type name=\"string\"/>\n"
+ " <type name=\"uint8\"/>\n"
+ "</md:annotation></module>";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Duplicate keyword \"type\".",
+ "/aa:{extension='md:annotation'}/aa");
+
+ /* duplication of the same annotation */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
+ "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
+ "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
+ "<md:annotation name=\"aa\">\n"
+ " <type name=\"string\"/>\n"
+ "</md:annotation><md:annotation name=\"aa\">\n"
+ " <type name=\"uint8\"/>\n"
+ "</md:annotation></module>";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Extension md:annotation is instantiated multiple times.",
+ "/aa:{extension='md:annotation'}/aa");
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_yang),
+ UTEST(test_yin),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/extensions/test_nacm.c b/tests/utests/extensions/test_nacm.c
new file mode 100644
index 0000000..1c999fb
--- /dev/null
+++ b/tests/utests/extensions/test_nacm.c
@@ -0,0 +1,124 @@
+/*
+ * @file test_nacm.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for NACM extensions support
+ *
+ * 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 "libyang.h"
+
+static int
+setup(void **state)
+{
+ UTEST_SETUP;
+
+ 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-acm", "2018-02-14", NULL));
+
+ return 0;
+}
+
+static void
+test_deny_all(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_node_container *cont;
+ struct lysc_node_leaf *leaf;
+ struct lysc_ext_instance *e;
+
+ const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:nacm:a; prefix en;"
+ "import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
+ "container a { nacm:default-deny-all; leaf aa {type string;}}"
+ "leaf b {type string;}}";
+
+ /* valid data */
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(cont = (struct lysc_node_container *)mod->compiled->data);
+ assert_non_null(leaf = (struct lysc_node_leaf *)cont->child);
+ assert_non_null(e = &cont->exts[0]);
+ assert_int_equal(LY_ARRAY_COUNT(cont->exts), 1);
+ assert_int_equal(LY_ARRAY_COUNT(leaf->exts), 1); /* NACM extensions inherit */
+ assert_ptr_equal(e->def, leaf->exts[0].def);
+ assert_int_equal(1, *((uint8_t *)e->compiled)); /* plugin's value for default-deny-all */
+ assert_null(cont->next->exts);
+
+ /* ignored - valid with warning */
+ data = "module b {yang-version 1.1; namespace urn:tests:extensions:nacm:b; prefix en;"
+ "import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
+ "nacm:default-deny-all;}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
+ "Extension nacm:default-deny-all is allowed only in a data nodes, but it is placed in \"module\" statement.",
+ "/b:{extension='nacm:default-deny-all'}");
+
+ /* invalid */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:nacm:aa; prefix en;"
+ "import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
+ "leaf l { type string; nacm:default-deny-all; nacm:default-deny-write;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
+ "Extension nacm:default-deny-write is mixed with nacm:default-deny-all.",
+ "/aa:l/{extension='nacm:default-deny-all'}");
+}
+
+static void
+test_deny_write(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_node_container *cont;
+ struct lysc_node_leaf *leaf;
+ struct lysc_ext_instance *e;
+
+ const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:nacm:a; prefix en;"
+ "import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
+ "container a { nacm:default-deny-write; leaf aa {type string;}}"
+ "leaf b {type string;}}";
+
+ /* valid data */
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(cont = (struct lysc_node_container *)mod->compiled->data);
+ assert_non_null(leaf = (struct lysc_node_leaf *)cont->child);
+ assert_non_null(e = &cont->exts[0]);
+ assert_int_equal(LY_ARRAY_COUNT(cont->exts), 1);
+ assert_int_equal(LY_ARRAY_COUNT(leaf->exts), 1); /* NACM extensions inherit */
+ assert_ptr_equal(e->def, leaf->exts[0].def);
+ assert_int_equal(2, *((uint8_t *)e->compiled)); /* plugin's value for default-deny-write */
+
+ /* ignored - valid with warning */
+ data = "module b {yang-version 1.1; namespace urn:tests:extensions:nacm:b; prefix en;"
+ "import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
+ "notification notif {nacm:default-deny-write;}}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
+ "Extension nacm:default-deny-write is not allowed in notification statement.",
+ "/b:notif/{extension='nacm:default-deny-write'}");
+
+ /* invalid */
+ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:nacm:aa; prefix en;"
+ "import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
+ "leaf l { type string; nacm:default-deny-write; nacm:default-deny-write;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
+ "Extension nacm:default-deny-write is instantiated multiple times.",
+ "/aa:l/{extension='nacm:default-deny-write'}");
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_deny_all, setup),
+ UTEST(test_deny_write, setup),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/extensions/test_schema_mount.c b/tests/utests/extensions/test_schema_mount.c
new file mode 100644
index 0000000..be879ec
--- /dev/null
+++ b/tests/utests/extensions/test_schema_mount.c
@@ -0,0 +1,1566 @@
+/**
+ * @file test_schema_mount.c
+ * @author Tadeas Vintrlik <xvintr04@stud.fit.vutbr.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief unit tests for Schema Mount extension support
+ *
+ * Copyright (c) 2021 - 2022 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"
+
+void **glob_state;
+
+static int
+setup(void **state)
+{
+ const char *schema =
+ "module sm {yang-version 1.1;namespace \"urn:sm\";prefix \"sm\";"
+ "import ietf-yang-schema-mount {prefix yangmnt;}"
+ "import ietf-interfaces {prefix if;}"
+ "container root {yangmnt:mount-point \"root\";}"
+ "container root2 {yangmnt:mount-point \"root\";}"
+ "container root3 {"
+ " list ls { key name; leaf name {type string;}"
+ " yangmnt:mount-point \"mnt-root\";"
+ " }"
+ "}"
+ "container root4 {config false; yangmnt:mount-point \"root\";}"
+ "leaf target{type string;}"
+ "augment /if:interfaces/if:interface {"
+ " leaf sm-name {type leafref {path \"/sm:target\";}}"
+ "}"
+ "}";
+
+ UTEST_SETUP;
+ glob_state = state;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "iana-if-type", NULL, NULL));
+
+ return 0;
+}
+
+static void
+test_schema(void **state)
+{
+ struct lys_module *mod;
+ const char *schema;
+ char *str;
+
+ /* invalid */
+ schema =
+ "module sm {\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " container root {\n"
+ " yangmnt:mount-point \"root\";\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Extension \"yangmnt:mount-point\" instance not allowed in YANG version 1 module.",
+ "/sm:root/{extension='yangmnt:mount-point'}/root");
+
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " yangmnt:mount-point \"root\";\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Extension \"yangmnt:mount-point\" instance allowed only in container or list statement.",
+ "/sm:{extension='yangmnt:mount-point'}/root");
+
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " container root {\n"
+ " leaf l {\n"
+ " type empty;\n"
+ " yangmnt:mount-point \"root\";\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Extension \"yangmnt:mount-point\" instance allowed only in container or list statement.",
+ "/sm:root/l/{extension='yangmnt:mount-point'}/root");
+
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " list l {\n"
+ " key \"k\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " yangmnt:mount-point \"root\";\n"
+ " yangmnt:mount-point \"root2\";\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Multiple extension \"yangmnt:mount-point\" instances.",
+ "/sm:l/{extension='yangmnt:mount-point'}/root");
+
+ /* valid */
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " container root {\n"
+ " yangmnt:mount-point \"root\";\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ lys_print_mem(&str, mod, LYS_OUT_YANG, 0);
+ assert_string_equal(str, schema);
+ free(str);
+}
+
+static LY_ERR
+test_ext_data_clb(const struct lysc_ext_instance *ext, void *user_data, void **ext_data, ly_bool *ext_data_free)
+{
+ void **state = glob_state;
+ struct lyd_node *data = NULL;
+
+ (void)ext;
+
+ if (user_data) {
+ CHECK_PARSE_LYD_PARAM(user_data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ }
+
+ *ext_data = data;
+ *ext_data_free = 1;
+ return LY_SUCCESS;
+}
+
+static void
+test_parse_invalid(void **state)
+{
+ const char *xml, *json;
+ struct lyd_node *data;
+
+ /* no callback set */
+ xml =
+ "<root xmlns=\"urn:sm\">"
+ " <unknown xmlns=\"unknown\">"
+ " <interface>"
+ " <name>bu</name>"
+ " <type xmlns:ii=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ii:ethernetCsmacd</type>"
+ " </interface>"
+ " </unknown>"
+ "</root>";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EINVAL, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": Failed to get extension data, no callback set.",
+ NULL);
+
+ json =
+ "{"
+ " \"sm:root\": {"
+ " \"unknown:unknown\": {"
+ " \"interface\": ["
+ " {"
+ " \"name\": \"bu\","
+ " \"type\": \"iana-if-type:ethernetCsmacd\""
+ " }"
+ " ]"
+ " }"
+ " }"
+ "}";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EINVAL, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": Failed to get extension data, no callback set.",
+ NULL);
+
+ /* unknown data */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, NULL);
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ assert_string_equal(LYD_NAME(data), "root");
+ assert_null(lyd_child(data));
+ assert_non_null(data->next);
+ assert_true(data->next->flags & LYD_DEFAULT);
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("No module with namespace \"unknown\" in the context.",
+ "Data location \"/sm:root\", line number 1.");
+
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ assert_string_equal(LYD_NAME(data), "root");
+ assert_null(lyd_child(data));
+ assert_non_null(data->next);
+ assert_true(data->next->flags & LYD_DEFAULT);
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("No module named \"unknown\" in the context.",
+ "Data location \"/sm:root\", line number 1.");
+
+ /* missing required callback data */
+ xml =
+ "<root xmlns=\"urn:sm\">"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">"
+ " <interface>"
+ " <name>bu</name>"
+ " </interface>"
+ " </interfaces>"
+ "</root>";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Data location \"/sm:root\", line number 1.");
+
+ json =
+ "{"
+ " \"sm:root\": {"
+ " \"ietf-interfaces:interfaces\": {"
+ " \"interface\": ["
+ " {"
+ " \"name\": \"bu\""
+ " }"
+ " ]"
+ " }"
+ " }"
+ "}";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Data location \"/sm:root\", line number 1.");
+
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Data location \"/sm:root\", line number 1.");
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Data location \"/sm:root\", line number 1.");
+
+ /* missing module in yang-library data */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Data location \"/sm:root\", line number 1.");
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Data location \"/sm:root\", line number 1.");
+
+ /* callback data correct, invalid YANG data */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Mandatory node \"type\" instance does not exist.",
+ "Schema location \"/ietf-interfaces:interfaces/interface/type\".");
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Mandatory node \"type\" instance does not exist.",
+ "Schema location \"/ietf-interfaces:interfaces/interface/type\".");
+
+ /* same validation fail in separate validation */
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
+ assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Mandatory node \"type\" instance does not exist.",
+ "Schema location \"/ietf-interfaces:interfaces/interface/type\".");
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
+ assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Mandatory node \"type\" instance does not exist.",
+ "Schema location \"/ietf-interfaces:interfaces/interface/type\".");
+ lyd_free_siblings(data);
+
+ /* success */
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ json =
+ "{\n"
+ " \"sm:root\": {\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_inline(void **state)
+{
+ const char *xml, *json;
+ char *lyb;
+ struct lyd_node *data;
+ const struct ly_ctx *ext_ctx;
+
+ /* valid */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ ext_ctx = LYD_CTX(lyd_child(data));
+ lyd_free_siblings(data);
+
+ json =
+ "{\n"
+ " \"sm:root\": {\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\"\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"ietf-interfaces:interfaces-state\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\",\n"
+ " \"oper-status\": \"not-present\",\n"
+ " \"statistics\": {\n"
+ " \"discontinuity-time\": \"2022-01-01T10:00:00-00:00\"\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+ lyd_free_siblings(data);
+
+ /* different yang-lib data with the same content-id */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-ip</name>"
+ " <revision>2014-06-16</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ assert_ptr_not_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+ ext_ctx = LYD_CTX(lyd_child(data));
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&lyb, data, LYD_LYB, 0));
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(lyb, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+ free(lyb);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_shared(void **state)
+{
+ const char *xml, *json;
+ char *lyb;
+ struct lyd_node *data;
+
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <shared-schema/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ json =
+ "{\n"
+ " \"sm:root\": {\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\"\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"ietf-interfaces:interfaces-state\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\",\n"
+ " \"oper-status\": \"not-present\",\n"
+ " \"statistics\": {\n"
+ " \"discontinuity-time\": \"2022-01-01T10:00:00-00:00\"\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ /* different yang-lib data */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-ip</name>"
+ " <revision>2014-06-16</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>2</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <shared-schema/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root2 xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root2>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Shared-schema yang-library content-id \"2\" differs from \"1\" used previously.",
+ "/ietf-yang-library:yang-library/content-id");
+
+ /* data for 2 mount points */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <shared-schema/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n"
+ "<root2 xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>fu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:fddi</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>fu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:fddi</type>\n"
+ " <oper-status>down</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2020-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root2>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ json =
+ "{\n"
+ " \"sm:root\": {\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\"\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"ietf-interfaces:interfaces-state\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\",\n"
+ " \"oper-status\": \"not-present\",\n"
+ " \"statistics\": {\n"
+ " \"discontinuity-time\": \"2022-01-01T10:00:00-00:00\"\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " },\n"
+ " \"sm:root2\": {\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"fu\",\n"
+ " \"type\": \"iana-if-type:fddi\"\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"ietf-interfaces:interfaces-state\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"fu\",\n"
+ " \"type\": \"iana-if-type:fddi\",\n"
+ " \"oper-status\": \"down\",\n"
+ " \"statistics\": {\n"
+ " \"discontinuity-time\": \"2020-01-01T10:00:00-00:00\"\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&lyb, data, LYD_LYB, LYD_PRINT_WITHSIBLINGS));
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(lyb, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ free(lyb);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_shared_parent_ref(void **state)
+{
+ const char *xml, *json;
+ struct lyd_node *data;
+
+ /* wrong leafref value */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>sm</name>"
+ " <namespace>urn:sm</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <namespace>"
+ " <prefix>smp</prefix>"
+ " <uri>urn:sm</uri>"
+ " </namespace>"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>mnt-root</label>"
+ " <shared-schema>"
+ " <parent-reference>/smp:target[. = current()/smp:name]</parent-reference>"
+ " </shared-schema>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root3 xmlns=\"urn:sm\">\n"
+ " <ls>\n"
+ " <name>target-value</name>\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <sm-name xmlns=\"urn:sm\">target-value</sm-name>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " </ls>\n"
+ "</root3>\n"
+ "<target xmlns=\"urn:sm\">wrong-target-value</target>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Invalid leafref value \"target-value\" - no target instance \"/sm:target\" with the same value.",
+ "Data location \"/ietf-interfaces:interfaces/interface[name='bu']/sm:sm-name\".");
+
+ json =
+ "{\n"
+ " \"sm:root3\": {\n"
+ " \"ls\": ["
+ " {\n"
+ " \"name\": \"target-value\",\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\",\n"
+ " \"sm:sm-name\": \"target-value\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"sm:target\": \"wrong-target-value\"\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": "
+ "Invalid leafref value \"target-value\" - no target instance \"/sm:target\" with the same value.",
+ "Data location \"/ietf-interfaces:interfaces/interface[name='bu']/sm:sm-name\".");
+
+ /* success */
+ xml =
+ "<root3 xmlns=\"urn:sm\">\n"
+ " <ls>\n"
+ " <name>target-value</name>\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <sm-name xmlns=\"urn:sm\">target-value</sm-name>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " </ls>\n"
+ "</root3>\n"
+ "<target xmlns=\"urn:sm\">target-value</target>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ json =
+ "{\n"
+ " \"sm:root3\": {\n"
+ " \"ls\": [\n"
+ " {\n"
+ " \"name\": \"target-value\",\n"
+ " \"ietf-interfaces:interfaces\": {\n"
+ " \"interface\": [\n"
+ " {\n"
+ " \"name\": \"bu\",\n"
+ " \"type\": \"iana-if-type:ethernetCsmacd\",\n"
+ " \"sm:sm-name\": \"target-value\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"sm:target\": \"target-value\"\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_config(void **state)
+{
+ const char *xml;
+ char *lyb;
+ struct lyd_node *data;
+ const struct lyd_node *node;
+
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <config>false</config>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <enabled>true</enabled>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+
+ node = lyd_child(data);
+ assert_string_equal(LYD_NAME(node), "interfaces");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "interface");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "name");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = node->next;
+ assert_string_equal(LYD_NAME(node), "type");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+
+ lyd_print_mem(&lyb, data, LYD_LYB, 0);
+ lyd_free_siblings(data);
+ CHECK_PARSE_LYD_PARAM(lyb, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ free(lyb);
+
+ node = lyd_child(data);
+ assert_string_equal(LYD_NAME(node), "interfaces");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "interface");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "name");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = node->next;
+ assert_string_equal(LYD_NAME(node), "type");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+
+ lyd_free_siblings(data);
+
+ /* the same effect but use a config false mount point instead of the separate metadata node */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root4 xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <enabled>true</enabled>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ "</root4>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+
+ node = lyd_child(data->next->next->next);
+ assert_string_equal(LYD_NAME(node), "interfaces");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "interface");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "name");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = node->next;
+ assert_string_equal(LYD_NAME(node), "type");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+
+ lyd_free_siblings(data);
+}
+
+static void
+test_new(void **state)
+{
+ const char *xml;
+ const struct lys_module *mod;
+ struct lyd_node *data, *node;
+
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+ "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+ " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+ " <module-set>"
+ " <name>test-set</name>"
+ " <module>"
+ " <name>ietf-datastores</name>"
+ " <revision>2018-02-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-yang-schema-mount</name>"
+ " <revision>2019-01-14</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-interfaces</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+ " </module>"
+ " <module>"
+ " <name>iana-if-type</name>"
+ " <revision>2014-05-08</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+ " </module>"
+ " <module>"
+ " <name>ietf-ip</name>"
+ " <revision>2014-06-16</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-ip</namespace>"
+ " </module>"
+ " <import-only-module>"
+ " <name>ietf-yang-types</name>"
+ " <revision>2013-07-15</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+ " </import-only-module>"
+ " </module-set>"
+ " <schema>"
+ " <name>test-schema</name>"
+ " <module-set>test-set</module-set>"
+ " </schema>"
+ " <datastore>"
+ " <name>ds:running</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <datastore>"
+ " <name>ds:operational</name>"
+ " <schema>test-schema</schema>"
+ " </datastore>"
+ " <content-id>1</content-id>"
+ "</yang-library>"
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+ " <module-set-id>1</module-set-id>"
+ "</modules-state>"
+ "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>root</label>"
+ " <shared-schema/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\">\n"
+ " <enabled>false</enabled>\n"
+ " </ipv4>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n";
+
+ /* create the data manually with simple new functions */
+ mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "sm");
+ assert_non_null(mod);
+ assert_int_equal(LY_SUCCESS, lyd_new_inner(NULL, mod, "root", 0, &data));
+
+ mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "ietf-interfaces");
+ assert_non_null(mod);
+ assert_int_equal(LY_SUCCESS, lyd_new_inner(data, mod, "interfaces", 0, &node));
+ assert_int_equal(LY_SUCCESS, lyd_new_list(node, NULL, "interface", 0, &node, "bu"));
+ assert_int_equal(LY_SUCCESS, lyd_new_term(node, NULL, "type", "iana-if-type:ethernetCsmacd", 0, NULL));
+ mod = ly_ctx_get_module_implemented(LYD_CTX(node), "ietf-ip");
+ assert_non_null(mod);
+ assert_int_equal(LY_SUCCESS, lyd_new_inner(node, mod, "ipv4", 0, &node));
+ assert_int_equal(LY_SUCCESS, lyd_new_term(node, NULL, "enabled", "false", 0, NULL));
+
+ mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "ietf-interfaces");
+ assert_non_null(mod);
+ assert_int_equal(LY_SUCCESS, lyd_new_inner(data, mod, "interfaces-state", 0, &node));
+ assert_int_equal(LY_SUCCESS, lyd_new_list(node, NULL, "interface", 0, &node, "bu"));
+ assert_int_equal(LY_SUCCESS, lyd_new_term(node, NULL, "type", "iana-if-type:ethernetCsmacd", 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_term(node, NULL, "oper-status", "not-present", 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_inner(node, NULL, "statistics", 0, &node));
+ assert_int_equal(LY_SUCCESS, lyd_new_term(node, NULL, "discontinuity-time", "2022-01-01T10:00:00-00:00", 0, NULL));
+
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ /* create the data using lyd_new_path */
+ assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX,
+ "/sm:root/ietf-interfaces:interfaces/interface[name='bu']/type", "iana-if-type:ethernetCsmacd", 0, &data));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(data, NULL,
+ "/sm:root/ietf-interfaces:interfaces/interface[name='bu']/ietf-ip:ipv4/enabled", "false", 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(data, NULL,
+ "/sm:root/ietf-interfaces:interfaces-state/interface[name='bu']/type", "iana-if-type:ethernetCsmacd", 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(data, NULL,
+ "/sm:root/ietf-interfaces:interfaces-state/interface[name='bu']/oper-status", "not-present", 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(data, NULL,
+ "/sm:root/ietf-interfaces:interfaces-state/interface[name='bu']/statistics/discontinuity-time",
+ "2022-01-01T10:00:00-00:00", 0, NULL));
+
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_schema),
+ UTEST(test_parse_invalid, setup),
+ UTEST(test_parse_inline, setup),
+ UTEST(test_parse_shared, setup),
+ UTEST(test_parse_shared_parent_ref, setup),
+ UTEST(test_parse_config, setup),
+ UTEST(test_new, setup),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/extensions/test_structure.c b/tests/utests/extensions/test_structure.c
new file mode 100644
index 0000000..23af450
--- /dev/null
+++ b/tests/utests/extensions/test_structure.c
@@ -0,0 +1,255 @@
+/**
+ * @file test_structure.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief unit tests for structure extensions support
+ *
+ * Copyright (c) 2022 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"
+
+static void
+test_schema(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ char *printed = NULL;
+ const char *data, *info;
+
+ /* valid data */
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct {"
+ " must \"/n2/l\";"
+ " status deprecated;"
+ " description desc;"
+ " reference no-ref;"
+ " typedef my-type {type string;}"
+ " grouping my-grp {leaf gl {type my-type;}}"
+ " container n1 {leaf l {config false; type uint32;}}"
+ " list n2 {leaf l {type leafref {path /n1/l;}}}"
+ " uses my-grp;"
+ "}}";
+
+ UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+
+ /* valid augment data */
+ data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "import a {prefix a;}"
+ "sx:augment-structure \"/a:struct/a:n1\" {"
+ " status obsolete;"
+ " reference none;"
+ " leaf aug-leaf {type string;}"
+ "}}";
+
+ UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+
+ /* yang compiled print */
+ info = "module a {\n"
+ " namespace \"urn:tests:extensions:structure:a\";\n"
+ " prefix a;\n"
+ "\n"
+ " ietf-yang-structure-ext:structure \"struct\" {\n"
+ " must \"/n2/l\";\n"
+ " status deprecated;\n"
+ " description\n"
+ " \"desc\";\n"
+ " reference\n"
+ " \"no-ref\";\n"
+ " container n1 {\n"
+ " status deprecated;\n"
+ " leaf l {\n"
+ " type uint32;\n"
+ " status deprecated;\n"
+ " }\n"
+ " leaf aug-leaf {\n"
+ " type string;\n"
+ " status obsolete;\n"
+ " }\n"
+ " }\n"
+ " list n2 {\n"
+ " min-elements 0;\n"
+ " max-elements 4294967295;\n"
+ " ordered-by user;\n"
+ " status deprecated;\n"
+ " leaf l {\n"
+ " type leafref {\n"
+ " path \"/n1/l\";\n"
+ " require-instance true;\n"
+ " type uint32;\n"
+ " }\n"
+ " status deprecated;\n"
+ " }\n"
+ " }\n"
+ " leaf gl {\n"
+ " type string;\n"
+ " status deprecated;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ assert_non_null(mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "a"));
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+
+ info = "module b {\n"
+ " namespace \"urn:tests:extensions:structure:b\";\n"
+ " prefix b;\n"
+ "\n"
+ " ietf-yang-structure-ext:augment-structure \"/a:struct/a:n1\";\n"
+ "}\n";
+
+ assert_non_null(mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "b"));
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+
+ /* no substatements */
+ data = "module c {yang-version 1.1; namespace urn:tests:extensions:structure:c; prefix c;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct;}";
+ info = "module c {\n"
+ " namespace \"urn:tests:extensions:structure:c\";\n"
+ " prefix c;\n"
+ "\n"
+ " ietf-yang-structure-ext:structure \"struct\";\n"
+ "}\n";
+
+ UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+}
+
+static void
+test_schema_invalid(void **state)
+{
+ const char *data;
+
+ /* structure */
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct {import yang;}}";
+ UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
+ CHECK_LOG_CTX("Invalid keyword \"import\" as a child of \"sx:structure struct\" extension instance.",
+ "/a:{extension='sx:structure'}/struct");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "container b { sx:structure struct { container x { leaf x {type string;}}}}}";
+ UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
+ CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": "
+ "Extension sx:structure must not be used as a non top-level statement in \"container\" statement.",
+ "/a:b/{extension='sx:structure'}/struct");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure { container x { leaf x {type string;}}}}";
+ UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL,
+ "Extension instance \"sx:structure\" missing argument element \"name\".", NULL);
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct { container x { leaf x {type string;}}}"
+ "sx:structure struct { container y { leaf y {type string;}}}}";
+ UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
+ CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": Extension sx:structure is instantiated multiple times.",
+ "/a:{extension='sx:structure'}/struct");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct { container x { leaf x {type string;}}}"
+ "choice struct { container y { leaf y {type string;}}}}";
+ UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
+ CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": Extension sx:structure collides with a choice with the same identifier.",
+ "/a:{extension='sx:structure'}/struct");
+
+ /* augment-structure */
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct {"
+ " container n1 {leaf l {config false; type uint32;}}"
+ " list n2 {leaf l {type string;}}"
+ "}"
+ "container n1 {leaf l2 {type uint8;}}}";
+ UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, NULL);
+
+ data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "import a {prefix a;}"
+ "sx:augment-structure \"/a:n1\" {"
+ " leaf aug-leaf {type string;}"
+ "}}";
+ UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_ENOTFOUND);
+ CHECK_LOG_CTX("Augment extension target node \"/a:n1\" from module \"b\" was not found.",
+ "/b:{extension='sx:augment-structure'}/{augment='/a:n1'}");
+}
+
+static void
+test_parse(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ struct lyd_node *tree = NULL;
+ const char *yang;
+ const char *xml = "<x xmlns=\"urn:tests:extensions:structure:a\">"
+ "<x>test</x>"
+ "<x2 xmlns=\"urn:tests:extensions:structure:b\">25</x2>"
+ "</x>";
+ const char *json = "{\"a:x\":{\"x\":\"test\",\"b:x2\":25}}";
+
+ yang = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct { container x { leaf x { type string;}}}}";
+ UTEST_ADD_MODULE(yang, LYS_IN_YANG, NULL, &mod);
+
+ yang = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "import a {prefix a;}"
+ "sx:augment-structure \"/a:struct/a:x\" {"
+ " leaf x2 {type uint32;}"
+ "}}";
+ UTEST_ADD_MODULE(yang, LYS_IN_YANG, NULL, NULL);
+
+ /* get extension after recompilation */
+ assert_non_null(e = mod->compiled->exts);
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
+ assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(tree);
+
+ ly_in_memory(UTEST_IN, json);
+ assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(tree);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_schema),
+ UTEST(test_schema_invalid),
+ UTEST(test_parse),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/extensions/test_yangdata.c b/tests/utests/extensions/test_yangdata.c
new file mode 100644
index 0000000..8c0176f
--- /dev/null
+++ b/tests/utests/extensions/test_yangdata.c
@@ -0,0 +1,273 @@
+/*
+ * @file test_yangdata.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for yang-data extensions support
+ *
+ * Copyright (c) 2019-2021 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"
+
+static int
+setup(void **state)
+{
+ UTEST_SETUP;
+
+ 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));
+
+ return 0;
+}
+
+static void
+test_schema(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ char *printed = NULL;
+ const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "feature x;"
+ "rc:yang-data template { container x { list l { leaf x { type string;}} leaf y {if-feature x; type string; config false;}}}}";
+ const char *info = "module a {\n"
+ " namespace \"urn:tests:extensions:yangdata:a\";\n"
+ " prefix self;\n\n"
+ " ietf-restconf:yang-data \"template\" {\n"
+ " container x {\n"
+ " status current;\n"
+ " list l {\n" /* no key */
+ " min-elements 0;\n"
+ " max-elements 4294967295;\n"
+ " ordered-by user;\n"
+ " status current;\n"
+ " leaf x {\n"
+ " type string;\n"
+ " status current;\n"
+ " }\n"
+ " }\n"
+ " leaf y {\n" /* config and if-feature are ignored */
+ " type string;\n"
+ " status current;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ /* valid data */
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+
+ data = "module c {yang-version 1.1; namespace urn:tests:extensions:yangdata:c; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "grouping g { choice ch { container a {presence a; config false;} container b {presence b; config true;}}}"
+ "rc:yang-data template { uses g;}}";
+ info = "module c {\n"
+ " namespace \"urn:tests:extensions:yangdata:c\";\n"
+ " prefix self;\n\n"
+ " ietf-restconf:yang-data \"template\" {\n"
+ " choice ch {\n"
+ " status current;\n"
+ " case a {\n"
+ " status current;\n"
+ " container a {\n"
+ " presence \"true\";\n"
+ " status current;\n"
+ " }\n"
+ " }\n"
+ " case b {\n"
+ " status current;\n"
+ " container b {\n"
+ " presence \"true\";\n"
+ " status current;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+
+ /* ignored - valid with warning */
+ data = "module b {yang-version 1.1; namespace urn:tests:extensions:yangdata:b; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "container b { rc:yang-data template { container x { leaf x {type string;}}}}}";
+ info = "module b {\n"
+ " namespace \"urn:tests:extensions:yangdata:b\";\n"
+ " prefix self;\n\n"
+ " container b {\n"
+ " config true;\n"
+ " status current;\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_null(mod->compiled->exts);
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is ignored since it appears as a non top-level statement in \"container\" statement.",
+ "/b:b/{extension='rc:yang-data'}/template");
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+
+ /* sama data nodes name, but not conflicting */
+ data = "module d {yang-version 1.1; namespace urn:tests:extensions:yangdata:d; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "leaf d { type string;}"
+ "rc:yang-data template1 { container d {presence d;}}"
+ "rc:yang-data template2 { container d {presence d;}}}";
+ info = "module d {\n"
+ " namespace \"urn:tests:extensions:yangdata:d\";\n"
+ " prefix self;\n\n"
+ " ietf-restconf:yang-data \"template1\" {\n"
+ " container d {\n"
+ " presence \"true\";\n"
+ " status current;\n"
+ " }\n"
+ " }\n"
+ " ietf-restconf:yang-data \"template2\" {\n"
+ " container d {\n"
+ " presence \"true\";\n"
+ " status current;\n"
+ " }\n"
+ " }\n\n"
+ " leaf d {\n"
+ " type string;\n"
+ " config true;\n"
+ " status current;\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 2);
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+}
+
+static void
+test_schema_invalid(void **state)
+{
+ const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template { leaf x {type string;}}}";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid keyword \"leaf\" as a child of \"rc:yang-data template\" extension instance.",
+ "/a:{extension='rc:yang-data'}/template");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template { choice x { leaf x {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is instantiated with leaf top level data node (inside a choice), "
+ "but only a single container data node is allowed.",
+ "/a:{extension='rc:yang-data'}/template");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template { choice x { case x { container z {presence ppp;} leaf x {type string;}}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is instantiated with multiple top level data nodes (inside a single choice's case), "
+ "but only a single container data node is allowed.",
+ "/a:{extension='rc:yang-data'}/template");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template { container x { leaf x {type string;}} container y { leaf y {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is instantiated with multiple top level data nodes, "
+ "but only a single container data node is allowed.",
+ "/a:{extension='rc:yang-data'}/template");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template;}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is instantiated without any top level data node, "
+ "but exactly one container data node is expected.",
+ "/a:{extension='rc:yang-data'}/template");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data { container x { leaf x {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL,
+ "Extension instance \"rc:yang-data\" missing argument element \"name\".", NULL);
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template { container x { leaf x {type string;}}}"
+ "rc:yang-data template { container y { leaf y {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is instantiated multiple times.",
+ "/a:{extension='rc:yang-data'}/template");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "grouping t { leaf-list x {type string;}}"
+ "rc:yang-data template { uses t;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
+ "Extension rc:yang-data is instantiated with leaf-list top level data node, "
+ "but only a single container data node is allowed.",
+ "/a:{extension='rc:yang-data'}/template");
+}
+
+static void
+test_parse(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ struct lyd_node *tree = NULL;
+ const char *schema = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template { container x { leaf x { type string;}}}}";
+ const char *xml = "<x xmlns=\"urn:tests:extensions:yangdata:a\"><x>test</x></x>";
+ const char *json = "{\"a:x\":{\"x\":\"test\"}}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
+ assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(tree);
+
+ ly_in_memory(UTEST_IN, json);
+ assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+
+ lyd_free_all(tree);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_schema, setup),
+ UTEST(test_schema_invalid, setup),
+ UTEST(test_parse, setup),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}