From cd07912073c951b4bbb871ed2653af1be2cfc714 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:55:11 +0200 Subject: Adding upstream version 2.1.30. Signed-off-by: Daniel Baumann --- tests/utests/data/test_diff.c | 1221 +++++++++++++++ tests/utests/data/test_lyb.c | 2841 ++++++++++++++++++++++++++++++++++ tests/utests/data/test_merge.c | 756 +++++++++ tests/utests/data/test_new.c | 446 ++++++ tests/utests/data/test_parser_json.c | 793 ++++++++++ tests/utests/data/test_parser_xml.c | 836 ++++++++++ tests/utests/data/test_printer_xml.c | 343 ++++ tests/utests/data/test_tree_data.c | 597 +++++++ tests/utests/data/test_validation.c | 1460 +++++++++++++++++ 9 files changed, 9293 insertions(+) create mode 100644 tests/utests/data/test_diff.c create mode 100644 tests/utests/data/test_lyb.c create mode 100644 tests/utests/data/test_merge.c create mode 100644 tests/utests/data/test_new.c create mode 100644 tests/utests/data/test_parser_json.c create mode 100644 tests/utests/data/test_parser_xml.c create mode 100644 tests/utests/data/test_printer_xml.c create mode 100644 tests/utests/data/test_tree_data.c create mode 100644 tests/utests/data/test_validation.c (limited to 'tests/utests/data') diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c new file mode 100644 index 0000000..1b7592a --- /dev/null +++ b/tests/utests/data/test_diff.c @@ -0,0 +1,1221 @@ +/** + * @file test_diff.c + * @author Radek Krejci + * @author Michal Vasko + * @brief tests for lyd_diff() + * + * 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 CHECK_PARSE_LYD(INPUT, MODEL) \ + CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, MODEL) + +#define CHECK_LYD_STRING(IN_MODEL, TEXT) \ + CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS) + +#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OUT_MODEL) \ + assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, 0, &OUT_MODEL));\ + assert_non_null(OUT_MODEL) + +#define TEST_DIFF_3(XML1, XML2, XML3, DIFF1, DIFF2, MERGE) \ + { \ + struct lyd_node *data1;\ + struct lyd_node *data2;\ + struct lyd_node *data3;\ + /*create*/\ + CHECK_PARSE_LYD(XML1, data1);\ + CHECK_PARSE_LYD(XML2, data2);\ + CHECK_PARSE_LYD(XML3, data3);\ + /* diff1 */ \ + struct lyd_node *diff1;\ + CHECK_PARSE_LYD_DIFF(data1, data2, diff1); \ + CHECK_LYD_STRING(diff1, DIFF1); \ + assert_int_equal(lyd_diff_apply_all(&data1, diff1), LY_SUCCESS); \ + CHECK_LYD(data1, data2); \ + /* diff2 */ \ + struct lyd_node *diff2;\ + CHECK_PARSE_LYD_DIFF(data2, data3, diff2); \ + CHECK_LYD_STRING(diff2, DIFF2); \ + assert_int_equal(lyd_diff_apply_all(&data2, diff2), LY_SUCCESS);\ + CHECK_LYD(data2, data3);\ + /* merge */ \ + assert_int_equal(lyd_diff_merge_all(&diff1, diff2, 0), LY_SUCCESS);\ + CHECK_LYD_STRING(diff1, MERGE); \ + /* cleanup */ \ + lyd_free_all(data1);\ + lyd_free_all(data2);\ + lyd_free_all(data3);\ + lyd_free_all(diff1);\ + lyd_free_all(diff2);\ + } + +const char *schema1 = + "module defaults {\n" + " yang-version 1.1;\n" + " namespace \"urn:libyang:tests:defaults\";\n" + " prefix df;\n" + "" + " feature unhide;\n" + "" + " typedef defint32 {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " leaf hiddenleaf {\n" + " if-feature \"unhide\";\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " container df {\n" + " leaf foo {\n" + " type defint32;\n" + " }\n" + "" + " leaf hiddenleaf {\n" + " if-feature \"unhide\";\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " container bar {\n" + " presence \"\";\n" + " leaf hi {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " leaf ho {\n" + " type int32;\n" + " mandatory true;\n" + " }\n" + " }\n" + "" + " leaf-list llist {\n" + " type defint32;\n" + " ordered-by user;\n" + " }\n" + "" + " list ul {\n" + " key \"l1\";\n" + " ordered-by user;\n" + " leaf l1 {\n" + " type string;\n" + " }\n" + "" + " leaf l2 {\n" + " type int32;\n" + " }\n" + " }\n" + "" + " leaf-list dllist {\n" + " type uint8;\n" + " default \"1\";\n" + " default \"2\";\n" + " default \"3\";\n" + " }\n" + "" + " list list {\n" + " key \"name\";\n" + " leaf name {\n" + " type string;\n" + " }\n" + "" + " leaf value {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + " list list2 {\n" + " key \"name2\";\n" + " leaf name2 {\n" + " type string;\n" + " }\n" + " leaf value2 {\n" + " type int32;\n" + " }\n" + " }\n" + " }\n"; +const char *schema2 = + " choice select {\n" + " default \"a\";\n" + " case a {\n" + " choice a {\n" + " leaf a1 {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " leaf a2 {\n" + " type int32;\n" + " default \"24\";\n" + " }\n" + " }\n" + " }\n" + "" + " leaf b {\n" + " type string;\n" + " }\n" + "" + " container c {\n" + " presence \"\";\n" + " leaf x {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + " }\n" + " }\n" + "" + " choice select2 {\n" + " default \"s2b\";\n" + " leaf s2a {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " case s2b {\n" + " choice s2b {\n" + " default \"b1\";\n" + " case b1 {\n" + " leaf b1_1 {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " leaf b1_2 {\n" + " type string;\n" + " }\n" + "" + " leaf b1_status {\n" + " type int32;\n" + " default \"42\";\n" + " config false;\n" + " }\n" + " }\n" + "" + " leaf b2 {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + " }\n" + " }\n" + " }\n" + " list kl {\n" + " config \"false\";\n" + " leaf l1 {\n" + " type string;\n" + " }\n" + "" + " leaf l2 {\n" + " type int32;\n" + " }\n" + " }\n" + "" + " leaf-list kll {\n" + " config \"false\";\n" + " type string;\n" + " }\n" + " }\n" + "" + " container hidden {\n" + " leaf foo {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " leaf baz {\n" + " type int32;\n" + " default \"42\";\n" + " }\n" + "" + " leaf papa {\n" + " type int32;\n" + " default \"42\";\n" + " config false;\n" + " }\n" + " }\n" + "" + " rpc rpc1 {\n" + " input {\n" + " leaf inleaf1 {\n" + " type string;\n" + " }\n" + "" + " leaf inleaf2 {\n" + " type string;\n" + " default \"def1\";\n" + " }\n" + " }\n" + "" + " output {\n" + " leaf outleaf1 {\n" + " type string;\n" + " default \"def2\";\n" + " }\n" + "" + " leaf outleaf2 {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + "" + " notification notif {\n" + " leaf ntfleaf1 {\n" + " type string;\n" + " default \"def3\";\n" + " }\n" + "" + " leaf ntfleaf2 {\n" + " type string;\n" + " }\n" + " }\n" + "}\n"; + +static int +setup(void **state) +{ + char *schema; + + UTEST_SETUP; + + /* create one schema, longer than 4095 chars */ + schema = malloc(strlen(schema1) + strlen(schema2) + 1); + strcpy(schema, schema1); + strcat(schema, schema2); + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + free(schema); + + return 0; +} + +static void +test_invalid(void **state) +{ + (void) state; + const char *xml = "42"; + + struct lyd_node *model_1; + + CHECK_PARSE_LYD(xml, model_1); + + struct lyd_node *diff = NULL; + + assert_int_equal(lyd_diff_siblings(model_1, lyd_child(model_1), 0, &diff), LY_EINVAL); + assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, NULL), LY_EINVAL); + + lyd_free_all(model_1); + lyd_free_all(diff); +} + +static void +test_same(void **state) +{ + (void) state; + const char *xml = + "\n" + " true\n" + " permit\n" + " deny\n" + " permit\n" + " true\n" + "\n" + " 4242\n" + "\n" + " 4242\n"; + + struct lyd_node *model_1; + struct lyd_node *model_2; + + 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)); + + CHECK_PARSE_LYD(xml, model_1); + CHECK_PARSE_LYD(xml, model_2); + + struct lyd_node *diff = NULL; + + assert_int_equal(lyd_diff_siblings(model_1, model_2, 0, &diff), LY_SUCCESS); + assert_null(diff); + assert_int_equal(lyd_diff_apply_all(&model_1, diff), LY_SUCCESS); + CHECK_LYD(model_1, model_2); + + lyd_free_all(model_1); + lyd_free_all(model_2); + lyd_free_all(diff); +} + +static void +test_empty1(void **state) +{ + (void) state; + const char *xml_in = + "\n" + " 42\n" + " 42\n" + "\n" + "\n" + " 42\n" + " 42\n" + "\n"; + + struct lyd_node *model_1 = NULL; + struct lyd_node *model_2; + + CHECK_PARSE_LYD(xml_in, model_2); + + struct lyd_node *diff; + + CHECK_PARSE_LYD_DIFF(model_1, model_2, diff); + CHECK_LYD_STRING(diff, + "\n" + " 42\n" + " 42\n" + "\n" + "\n" + " 42\n" + " 42\n" + "\n"); + assert_int_equal(lyd_diff_apply_all(&model_1, diff), LY_SUCCESS); + CHECK_LYD(model_1, model_2); + + lyd_free_all(model_1); + lyd_free_all(model_2); + lyd_free_all(diff); +} + +static void +test_empty2(void **state) +{ + (void) state; + const char *xml = "\n" + " 42\n" + " 42\n" + "\n" + " 42\n" + " 42\n" + "\n"; + + struct lyd_node *model_1; + + CHECK_PARSE_LYD(xml, model_1); + + struct lyd_node *diff; + + CHECK_PARSE_LYD_DIFF(model_1, NULL, diff); + CHECK_LYD_STRING(diff, + "\n" + " 42\n" + " 42\n" + "\n" + "\n" + " 42\n" + " 42\n" + "\n"); + + assert_int_equal(lyd_diff_apply_all(&model_1, diff), LY_SUCCESS); + assert_ptr_equal(model_1, NULL); + + lyd_free_all(diff); + lyd_free_all(model_1); +} + +static void +test_empty_nested(void **state) +{ + (void) state; + const char *xml = "42"; + + struct lyd_node *model_1; + + CHECK_PARSE_LYD(xml, model_1); + + struct lyd_node *diff = NULL; + + assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, &diff), LY_SUCCESS); + assert_null(diff); + + struct lyd_node *diff1; + + CHECK_PARSE_LYD_DIFF(NULL, lyd_child(model_1), diff1); + CHECK_LYD_STRING(diff1, + "\n" + " 42\n" + "\n"); + + struct lyd_node *diff2; + + CHECK_PARSE_LYD_DIFF(lyd_child(model_1), NULL, diff2); + CHECK_LYD_STRING(diff2, + "\n" + " 42\n" + "\n"); + + lyd_free_all(model_1); + lyd_free_all(diff1); + lyd_free_all(diff2); +} + +static void +test_delete_merge(void **state) +{ + (void) state; + struct lyd_node *diff1, *diff2; + const char *xml1 = + "\n" + " \n" + " a\n" + " \n" + " a\n" + " \n" + " \n" + "\n"; + const char *xml2 = + "\n" + " \n" + " a\n" + " \n" + "\n"; + const char *xml_merge = + "\n" + " \n" + " a\n" + " \n" + " a\n" + " \n" + " \n" + "\n"; + + CHECK_PARSE_LYD(xml1, diff1); + CHECK_PARSE_LYD(xml2, diff2); + + assert_int_equal(lyd_diff_merge_all(&diff1, diff2, 0), LY_SUCCESS); + CHECK_LYD_STRING(diff1, xml_merge); + + lyd_free_all(diff1); + lyd_free_all(diff2); +} + +static void +test_leaf(void **state) +{ + (void) state; + const char *xml1 = + "\n" + " 42\n" + "\n" + "\n" + " 42\n" + " 42\n" + "\n"; + const char *xml2 = + "\n" + " 41\n" + " 42\n" + "\n"; + const char *xml3 = + "\n" + " 40\n" + "\n" + "\n" + " 40\n" + "\n"; + const char *out_diff_1 = + "\n" + " 41\n" + " 42\n" + "\n" + "\n" + " 42\n" + " 42\n" + "\n"; + + const char *out_diff_2 = "\n" + " 40\n" + " 42\n" + "\n" + "\n" + " 40\n" + "\n"; + + const char *out_merge = + "\n" + " 40\n" + "\n" + "\n" + " 40\n" + " 42\n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_list(void **state) +{ + (void) state; + const char *xml1 = "\n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " b\n" + " 2\n" + " \n" + "\n"; + const char *xml2 = "\n" + " \n" + " b\n" + " -2\n" + " \n" + " \n" + " c\n" + " 3\n" + " \n" + "\n"; + const char *xml3 = "\n" + " \n" + " b\n" + " -2\n" + " \n" + " \n" + " a\n" + " 2\n" + " \n" + "\n"; + + const char *out_diff_1 = + "\n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " b\n" + " -2\n" + " \n" + " \n" + " c\n" + " 3\n" + " \n" + "\n"; + const char *out_diff_2 = + "\n" + " \n" + " c\n" + " 3\n" + " \n" + " \n" + " a\n" + " 2\n" + " \n" + "\n"; + const char *out_merge = + "\n" + " \n" + " a\n" + " 2\n" + " \n" + " \n" + " b\n" + " -2\n" + " \n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_userord_llist(void **state) +{ + (void) state; + const char *xml1 = + "\n" + " 1\n" + " 2\n" + " 3\n" + " 4\n" + " 5\n" + "\n"; + const char *xml2 = + "\n" + " 1\n" + " 4\n" + " 3\n" + " 2\n" + " 5\n" + "\n"; + const char *xml3 = + "\n" + " 5\n" + " 4\n" + " 3\n" + " 2\n" + "\n"; + + const char *out_diff_1 = + "\n" + " 4\n" + " 3\n" + "\n"; + const char *out_diff_2 = + "\n" + " 1\n" + " 5\n" + "\n"; + const char *out_merge = + "\n" + " 4\n" + " 3\n" + " 1\n" + " 5\n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_userord_llist2(void **state) +{ + (void) state; + const char *xml1 = + "\n" + " 1\n" + " a1\n" + " 2\n" + " 3\n" + " 4\n" + "\n"; + const char *xml2 = + "\n" + " 1\n" + " a1\n" + " 2\n" + " 4\n" + " 3\n" + "\n"; + const char *xml3 = + "\n" + " 4\n" + " 1\n" + " a1\n" + " 3\n" + "\n"; + + const char *out_diff_1 = + "\n" + " 4\n" + "\n"; + const char *out_diff_2 = + "\n" + " 2\n" + " 4\n" + "\n"; + const char *out_merge = + "\n" + " 4\n" + " 2\n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_userord_mix(void **state) +{ + (void) state; + const char *xml1 = + "\n" + " 1\n" + " 2\n" + " 3\n" + "\n"; + const char *xml2 = + "\n" + " 3\n" + " 1\n" + "\n"; + const char *xml3 = + "\n" + " 1\n" + " 4\n" + " 3\n" + "\n"; + + const char *out_diff_1 = + "\n" + " 2\n" + " 3\n" + "\n"; + const char *out_diff_2 = + "\n" + " 1\n" + " 4\n" + "\n"; + const char *out_merge = + "\n" + " 2\n" + " 3\n" + " 1\n" + " 4\n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_userord_list(void **state) +{ + (void) state; + const char *xml1 = + "\n" + "
    \n" + " a\n" + " 1\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
    \n" + " c\n" + " 3\n" + "
\n" + "
\n"; + const char *xml2 = + "\n" + "
    \n" + " a\n" + " 11\n" + "
\n" + "
    \n" + " c\n" + " 3\n" + "
\n" + "
\n"; + const char *xml3 = + "\n" + "
    \n" + " c\n" + " 33\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
\n"; + + const char *out_diff_1 = + "\n" + "
    \n" + " a\n" + " 11\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
\n"; + const char *out_diff_2 = + "\n" + "
    \n" + " a\n" + " 11\n" + "
\n" + "
    \n" + " c\n" + " 33\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
\n"; + const char *out_merge = + "\n" + "
    \n" + " a\n" + " 1\n" + "
\n" + "
    \n" + " b\n" + "
\n" + "
    \n" + " c\n" + " 33\n" + "
\n" + "
\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_userord_list2(void **state) +{ + (void) state; + const char *xml1 = + "\n" + "
    \n" + " d\n" + " 4\n" + "
\n" + "
\n"; + const char *xml2 = + "\n" + "
    \n" + " c\n" + " 3\n" + "
\n" + "
    \n" + " d\n" + " 4\n" + "
\n" + "
\n"; + const char *xml3 = + "\n" + "
    \n" + " a\n" + " 1\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
    \n" + " c\n" + " 3\n" + "
\n" + "
    \n" + " d\n" + " 4\n" + "
\n" + "
\n"; + + const char *out_diff_1 = + "\n" + "
    \n" + " c\n" + " 3\n" + "
\n" + "
\n"; + const char *out_diff_2 = + "\n" + "
    \n" + " a\n" + " 1\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
\n"; + const char *out_merge = + "\n" + "
    \n" + " c\n" + " 3\n" + "
\n" + "
    \n" + " a\n" + " 1\n" + "
\n" + "
    \n" + " b\n" + " 2\n" + "
\n" + "
\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_keyless_list(void **state) +{ + (void) state; + const char *xml1 = "\n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " b\n" + " 2\n" + " \n" + " \n" + " c\n" + " 3\n" + " \n" + "\n"; + const char *xml2 = "\n" + " \n" + " b\n" + " 2\n" + " \n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " a\n" + " 1\n" + " \n" + "\n"; + const char *xml3 = "\n" + " \n" + " c\n" + " \n" + " \n" + " 4\n" + " \n" + " \n" + " e\n" + " 5\n" + " \n" + " \n" + " f\n" + " 6\n" + " \n" + "\n"; + + const char *out_diff_1 = + "\n" + " \n" + " c\n" + " 3\n" + " \n" + " \n" + " b\n" + " 2\n" + " \n" + " \n" + " a\n" + " 1\n" + " \n" + "\n"; + const char *out_diff_2 = + "\n" + " \n" + " b\n" + " 2\n" + " \n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " c\n" + " \n" + " \n" + " 4\n" + " \n" + " \n" + " e\n" + " 5\n" + " \n" + " \n" + " f\n" + " 6\n" + " \n" + "\n"; + const char *out_merge = + "\n" + " \n" + " c\n" + " 3\n" + " \n" + " \n" + " b\n" + " 2\n" + " \n" + " \n" + " a\n" + " 1\n" + " \n" + " \n" + " c\n" + " \n" + " \n" + " 4\n" + " \n" + " \n" + " e\n" + " 5\n" + " \n" + " \n" + " f\n" + " 6\n" + " \n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_state_llist(void **state) +{ + (void) state; + const char *xml1 = "\n" + " a\n" + " b\n" + " c\n" + "\n"; + const char *xml2 = "\n" + " b\n" + " c\n" + " a\n" + " a\n" + " a\n" + "\n"; + const char *xml3 = "\n" + " a\n" + " d\n" + " a\n" + "\n"; + + const char *out_diff_1 = + "\n" + " b\n" + " c\n" + " a\n" + " a\n" + "\n"; + const char *out_diff_2 = + "\n" + " b\n" + " c\n" + " a\n" + " d\n" + "\n"; + const char *out_merge = + "\n" + " b\n" + " c\n" + " a\n" + " d\n" + "\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void +test_wd(void **state) +{ + (void) state; + const struct lys_module *mod; + const char *xml2 = "\n" + " 41\n" + " 4\n" + "\n"; + const char *xml3 = "\n" + " 42\n" + " 4\n" + " 1\n" + "\n"; + + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "defaults"); + assert_non_null(mod); + + struct lyd_node *model_1 = NULL; + + assert_int_equal(lyd_validate_module(&model_1, mod, 0, NULL), LY_SUCCESS); + assert_ptr_not_equal(model_1, NULL); + + struct lyd_node *model_2; + struct lyd_node *model_3; + + CHECK_PARSE_LYD_PARAM(xml2, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, model_2); + CHECK_PARSE_LYD_PARAM(xml3, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, model_3); + + /* diff1 */ + struct lyd_node *diff1 = NULL; + + assert_int_equal(lyd_diff_siblings(model_1, model_2, LYD_DIFF_DEFAULTS, &diff1), LY_SUCCESS); + assert_non_null(diff1); + + const char *diff1_out_1 = + "\n" + " 41\n" + " 1\n" + " 2\n" + " 3\n" + " 4\n" + "\n"; + + CHECK_LYD_STRING_PARAM(diff1, diff1_out_1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL); + assert_int_equal(lyd_diff_apply_all(&model_1, diff1), LY_SUCCESS); + CHECK_LYD(model_1, model_2); + + /* diff2 */ + struct lyd_node *diff2; + + assert_int_equal(lyd_diff_siblings(model_2, model_3, LYD_DIFF_DEFAULTS, &diff2), LY_SUCCESS); + assert_non_null(diff2); + CHECK_LYD_STRING(diff2, + "\n" + " 42\n" + " 1\n" + "\n"); + + assert_int_equal(lyd_diff_apply_all(&model_2, diff2), LY_SUCCESS); + CHECK_LYD(model_2, model_3); + + /* merge */ + assert_int_equal(lyd_diff_merge_all(&diff1, diff2, 0), LY_SUCCESS); + + const char *diff1_out_2 = + "\n" + " 42\n" + " 1\n" + " 2\n" + " 3\n" + " 4\n" + "\n"; + + CHECK_LYD_STRING_PARAM(diff1, diff1_out_2, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL); + + lyd_free_all(model_1); + lyd_free_all(model_2); + lyd_free_all(model_3); + lyd_free_all(diff1); + lyd_free_all(diff2); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + UTEST(test_invalid, setup), + UTEST(test_same, setup), + UTEST(test_empty1, setup), + UTEST(test_empty2, setup), + UTEST(test_empty_nested, setup), + UTEST(test_delete_merge, setup), + UTEST(test_leaf, setup), + UTEST(test_list, setup), + UTEST(test_userord_llist, setup), + UTEST(test_userord_llist2, setup), + UTEST(test_userord_mix, setup), + UTEST(test_userord_list, setup), + UTEST(test_userord_list2, setup), + UTEST(test_keyless_list, setup), + UTEST(test_state_llist, setup), + UTEST(test_wd, setup), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/utests/data/test_lyb.c b/tests/utests/data/test_lyb.c new file mode 100644 index 0000000..26f3e73 --- /dev/null +++ b/tests/utests/data/test_lyb.c @@ -0,0 +1,2841 @@ +/** + * @file test_lyb.c + * @author Michal Vasko + * @brief Cmocka tests for LYB binary data format. + * + * 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 "hash_table.h" +#include "libyang.h" + +#define CHECK_PARSE_LYD(INPUT, OUT_NODE) \ + CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, OUT_NODE) + +#define CHECK_LYD_STRING(MODEL, TEXT) \ + CHECK_LYD_STRING_PARAM(MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK) + +static void +check_print_parse(void **state, const char *data_xml) +{ + struct lyd_node *tree_1; + struct lyd_node *tree_2; + char *lyb_out; + + CHECK_PARSE_LYD(data_xml, tree_1); + assert_int_equal(lyd_print_mem(&lyb_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, lyb_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, + 0, &tree_2)); + assert_non_null(tree_2); + CHECK_LYD(tree_1, tree_2); + + free(lyb_out); + lyd_free_all(tree_1); + lyd_free_all(tree_2); +} + +static int +setup(void **state) +{ + UTEST_SETUP; + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG)); + + return 0; +} + +static void +tests_leaflist(void **state) +{ + const char *mod; + const char *data_xml; + + mod = + "module mod { namespace \"urn:test-leaflist\"; prefix m;" + " container cont {" + " presence \"\";" + " leaf-list ll {" + " type uint8;" + " }" + " }" + "}"; + UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL); + + data_xml = + "\n" + "\n"; + check_print_parse(state, data_xml); + + data_xml = + "\n" + " 1\n" + "\n"; + check_print_parse(state, data_xml); + + data_xml = + "\n" + " 1\n" + " 2\n" + "\n"; + check_print_parse(state, data_xml); +} + +static void +tests_list(void **state) +{ + const char *mod; + const char *data_xml; + + mod = + "module mod { namespace \"urn:test-list\"; prefix m;" + " container cont {" + " presence \"\";" + " list lst {" + " key \"lf\";" + " leaf lf {" + " type uint8;" + " }" + " }" + " }" + "}"; + UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL); + + data_xml = + "\n" + " " + " 1" + " " + "\n"; + check_print_parse(state, data_xml); + + data_xml = + "\n" + " " + " 1" + " 2" + " " + "\n"; + check_print_parse(state, data_xml); +} + +static void +tests_any(void **state) +{ + const char *mod; + const char *data_xml; + + mod = + "module mod { namespace \"urn:test-any\"; prefix m;" + " container cont {" + " presence \"\";" + " anyxml anxml;\n" + " }" + "}"; + UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL); + + data_xml = + "\n" + "\n"; + check_print_parse(state, data_xml); + + data_xml = + "\n" + " value\n" + "\n"; + check_print_parse(state, data_xml); + + data_xml = + "\n" + " value\n" + " value\n" + "\n"; + check_print_parse(state, data_xml); +} + +static void +test_ietf_interfaces(void **state) +{ + const char *data_xml = + "\n" + " \n" + " eth0\n" + " Ethernet 0\n" + " ianaift:ethernetCsmacd\n" + " true\n" + " \n" + " true\n" + " 1500\n" + "
\n" + " 192.168.2.100\n" + " 24\n" + "
\n" + "
\n" + "
\n" + " \n" + " eth1\n" + " Ethernet 1\n" + " ianaift:ethernetCsmacd\n" + " true\n" + " \n" + " true\n" + " 1500\n" + "
\n" + " 10.10.1.5\n" + " 16\n" + "
\n" + "
\n" + "
\n" + " \n" + " gigaeth0\n" + " GigabitEthernet 0\n" + " ianaift:ethernetCsmacd\n" + " false\n" + " \n" + "
\n"; + + assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-ip", NULL, NULL)); + assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "iana-if-type", NULL, NULL)); + + check_print_parse(state, data_xml); +} + +static void +test_origin(void **state) +{ + const char *origin_yang = + "module test-origin {" + " namespace \"urn:test-origin\";" + " prefix to;" + " import ietf-origin {" + " prefix or;" + " }" + "" + " container cont {" + " leaf leaf1 {" + " type string;" + " }" + " leaf leaf2 {" + " type string;" + " }" + " leaf leaf3 {" + " type uint8;" + " }" + " }" + "}"; + const char *data_xml = + "\n" + " value1\n" + " value2\n" + " 125\n" + "\n"; + + UTEST_ADD_MODULE(origin_yang, LYS_IN_YANG, NULL, NULL); + assert_int_equal(LY_SUCCESS, lys_set_implemented(ly_ctx_get_module_latest(UTEST_LYCTX, "ietf-origin"), NULL)); + + check_print_parse(state, data_xml); +} + +static void +test_statements(void **state) +{ + const char *links_yang = + "module links {\n" + " yang-version 1.1;\n" + " namespace \"urn:module2\";\n" + " prefix mod2;\n" + "\n" + " identity just-another-identity;\n" + "\n" + " leaf one-leaf {\n" + " type string;\n" + " }\n" + "\n" + " list list-for-augment {\n" + " key keyleaf;\n" + "\n" + " leaf keyleaf {\n" + " type string;\n" + " }\n" + "\n" + " leaf just-leaf {\n" + " type int32;\n" + " }\n" + " }\n" + "\n" + " leaf rleaf {\n" + " type string;\n" + " }\n" + "\n" + " leaf-list llist {\n" + " type string;\n" + " min-elements 0;\n" + " max-elements 100;\n" + " ordered-by user;\n" + " }\n" + "\n" + " grouping rgroup {\n" + " leaf rg1 {\n" + " type string;\n" + " }\n" + "\n" + " leaf rg2 {\n" + " type string;\n" + " }\n" + " }\n" + "}\n"; + + const char *statements_yang = + "module statements {\n" + " namespace \"urn:module\";\n" + " prefix mod;\n" + " yang-version 1.1;\n" + "\n" + " import links {\n" + " prefix mod2;\n" + " }\n" + "\n" + " identity random-identity {\n" + " base \"mod2:just-another-identity\";\n" + " base \"another-identity\";\n" + " }\n" + "\n" + " identity another-identity {\n" + " base \"mod2:just-another-identity\";\n" + " }\n" + "\n" + " typedef percent {\n" + " type uint8 {\n" + " range \"0 .. 100\";\n" + " }\n" + " units percent;\n" + " }\n" + "\n" + " container ice-cream-shop {\n" + " container employees {\n" + " list employee {\n" + " config true;\n" + " key id;\n" + " unique name;\n" + " min-elements 0;\n" + " max-elements 100;\n" + "\n" + " leaf id {\n" + " type uint64;\n" + " mandatory true;\n" + " }\n" + "\n" + " leaf name {\n" + " type string;\n" + " }\n" + "\n" + " leaf age {\n" + " type uint32;\n" + " }\n" + " }\n" + " }\n" + " }\n" + "\n" + " container random {\n" + " choice switch {\n" + " case a {\n" + " leaf aleaf {\n" + " type string;\n" + " default aaa;\n" + " }\n" + " }\n" + "\n" + " case c {\n" + " leaf cleaf {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + "\n" + " anyxml xml-data;\n" + " anydata any-data;\n" + " leaf-list leaflist {\n" + " type string;\n" + " min-elements 0;\n" + " max-elements 20;\n" + " ordered-by system;\n" + " }\n" + "\n" + " grouping group {\n" + " leaf g1 {\n" + " mandatory false;\n" + " type percent;\n" + " }\n" + "\n" + " leaf g2 {\n" + " type string;\n" + " }\n" + " }\n" + "\n" + " uses group;\n" + " uses mod2:rgroup;\n" + "\n" + " leaf lref {\n" + " type leafref {\n" + " path \"/mod2:one-leaf\";\n" + " }\n" + " }\n" + "\n" + " leaf iref {\n" + " type identityref {\n" + " base \"mod2:just-another-identity\";\n" + " }\n" + " }\n" + " }\n" + "\n" + " notification notif;\n" + "\n" + " augment \"/random\" {\n" + " leaf aug-leaf {\n" + " type string;\n" + " }\n" + " }\n" + "}\n"; + + const char *data_xml = + "reference leaf\n" + "\n" + " \n" + " \n" + " 0\n" + " John Doe\n" + " 28\n" + " \n" + " \n" + " 1\n" + " Dohn Joe\n" + " 20\n" + " \n" + " \n" + "\n" + "\n" + " string\n" + " data\n" + " \n" + " l0\n" + " l1\n" + " l2\n" + " 40\n" + " string\n" + " string\n" + " string\n" + " string\n" + " reference leaf\n" + " random-identity\n" + "\n"; + + UTEST_ADD_MODULE(links_yang, LYS_IN_YANG, NULL, NULL); + UTEST_ADD_MODULE(statements_yang, LYS_IN_YANG, NULL, NULL); + + check_print_parse(state, data_xml); +} + +static void +test_opaq(void **state) +{ + const char *nc_feats[] = {"writable-running", NULL}; + const char *data_xml = + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " TestFirst\n" + " \n" + " \n" + "\n"; + struct ly_in *in; + struct lyd_node *tree_1; + struct lyd_node *tree_2; + char *xml_out; /* tree_2 */ + LY_ERR rc; + + assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", NULL, nc_feats)); + + ly_in_new_memory(data_xml, &in); + rc = lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &tree_1, NULL); + ly_in_free(in, 0); + assert_int_equal(rc, LY_SUCCESS); + + assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); + + ly_in_new_memory(xml_out, &in); + rc = lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_LYB, LYD_TYPE_RPC_YANG, &tree_2, NULL); + ly_in_free(in, 0); + assert_int_equal(rc, LY_SUCCESS); + + /* compare models */ + CHECK_LYD(tree_1, tree_2); + + /* clean */ + free(xml_out); + lyd_free_all(tree_1); + lyd_free_all(tree_2); +} + +static void +test_collisions(void **state) +{ + char *counters_yang, *data_xml; + + counters_yang = malloc(32768); + strcpy(counters_yang, + "module counters {\n" + " namespace \"urn:counters\";\n" + " prefix c;\n" + "\n" + " container stats {\n"); + strcat(counters_yang, + " leaf counter1 {\n" + " type uint64;\n" + " }\n" + " leaf counter2 {\n" + " type uint64;\n" + " }\n" + " leaf counter3 {\n" + " type uint64;\n" + " }\n" + " leaf counter4 {\n" + " type uint64;\n" + " }\n" + " leaf counter5 {\n" + " type uint64;\n" + " }\n" + " leaf counter6 {\n" + " type uint64;\n" + " }\n" + " leaf counter7 {\n" + " type uint64;\n" + " }\n" + " leaf counter8 {\n" + " type uint64;\n" + " }\n" + " leaf counter9 {\n" + " type uint64;\n" + " }\n" + " leaf counter10 {\n" + " type uint64;\n" + " }\n" + " leaf counter11 {\n" + " type uint64;\n" + " }\n" + " leaf counter12 {\n" + " type uint64;\n" + " }\n" + " leaf counter13 {\n" + " type uint64;\n" + " }\n" + " leaf counter14 {\n" + " type uint64;\n" + " }\n" + " leaf counter15 {\n" + " type uint64;\n" + " }\n" + " leaf counter16 {\n" + " type uint64;\n" + " }\n" + " leaf counter17 {\n" + " type uint64;\n" + " }\n" + " leaf counter18 {\n" + " type uint64;\n" + " }\n" + " leaf counter19 {\n" + " type uint64;\n" + " }\n" + " leaf counter20 {\n" + " type uint64;\n" + " }\n" + " leaf counter21 {\n" + " type uint64;\n" + " }\n" + " leaf counter22 {\n" + " type uint64;\n" + " }\n" + " leaf counter23 {\n" + " type uint64;\n" + " }\n" + " leaf counter24 {\n" + " type uint64;\n" + " }\n" + " leaf counter25 {\n" + " type uint64;\n" + " }\n" + " leaf counter26 {\n" + " type uint64;\n" + " }\n" + " leaf counter27 {\n" + " type uint64;\n" + " }\n" + " leaf counter28 {\n" + " type uint64;\n" + " }\n" + " leaf counter29 {\n" + " type uint64;\n" + " }\n" + " leaf counter30 {\n" + " type uint64;\n" + " }\n" + " leaf counter31 {\n" + " type uint64;\n" + " }\n" + " leaf counter32 {\n" + " type uint64;\n" + " }\n" + " leaf counter33 {\n" + " type uint64;\n" + " }\n" + " leaf counter34 {\n" + " type uint64;\n" + " }\n" + " leaf counter35 {\n" + " type uint64;\n" + " }\n" + " leaf counter36 {\n" + " type uint64;\n" + " }\n" + " leaf counter37 {\n" + " type uint64;\n" + " }\n" + " leaf counter38 {\n" + " type uint64;\n" + " }\n" + " leaf counter39 {\n" + " type uint64;\n" + " }\n" + " leaf counter40 {\n" + " type uint64;\n" + " }\n" + " leaf counter41 {\n" + " type uint64;\n" + " }\n" + " leaf counter42 {\n" + " type uint64;\n" + " }\n" + " leaf counter43 {\n" + " type uint64;\n" + " }\n" + " leaf counter44 {\n" + " type uint64;\n" + " }\n" + " leaf counter45 {\n" + " type uint64;\n" + " }\n" + " leaf counter46 {\n" + " type uint64;\n" + " }\n" + " leaf counter47 {\n" + " type uint64;\n" + " }\n" + " leaf counter48 {\n" + " type uint64;\n" + " }\n" + " leaf counter49 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter50 {\n" + " type uint64;\n" + " }\n" + " leaf counter51 {\n" + " type uint64;\n" + " }\n" + " leaf counter52 {\n" + " type uint64;\n" + " }\n" + " leaf counter53 {\n" + " type uint64;\n" + " }\n" + " leaf counter54 {\n" + " type uint64;\n" + " }\n" + " leaf counter55 {\n" + " type uint64;\n" + " }\n" + " leaf counter56 {\n" + " type uint64;\n" + " }\n" + " leaf counter57 {\n" + " type uint64;\n" + " }\n" + " leaf counter58 {\n" + " type uint64;\n" + " }\n" + " leaf counter59 {\n" + " type uint64;\n" + " }\n" + " leaf counter60 {\n" + " type uint64;\n" + " }\n" + " leaf counter61 {\n" + " type uint64;\n" + " }\n" + " leaf counter62 {\n" + " type uint64;\n" + " }\n" + " leaf counter63 {\n" + " type uint64;\n" + " }\n" + " leaf counter64 {\n" + " type uint64;\n" + " }\n" + " leaf counter65 {\n" + " type uint64;\n" + " }\n" + " leaf counter66 {\n" + " type uint64;\n" + " }\n" + " leaf counter67 {\n" + " type uint64;\n" + " }\n" + " leaf counter68 {\n" + " type uint64;\n" + " }\n" + " leaf counter69 {\n" + " type uint64;\n" + " }\n" + " leaf counter70 {\n" + " type uint64;\n" + " }\n" + " leaf counter71 {\n" + " type uint64;\n" + " }\n" + " leaf counter72 {\n" + " type uint64;\n" + " }\n" + " leaf counter73 {\n" + " type uint64;\n" + " }\n" + " leaf counter74 {\n" + " type uint64;\n" + " }\n" + " leaf counter75 {\n" + " type uint64;\n" + " }\n" + " leaf counter76 {\n" + " type uint64;\n" + " }\n" + " leaf counter77 {\n" + " type uint64;\n" + " }\n" + " leaf counter78 {\n" + " type uint64;\n" + " }\n" + " leaf counter79 {\n" + " type uint64;\n" + " }\n" + " leaf counter80 {\n" + " type uint64;\n" + " }\n" + " leaf counter81 {\n" + " type uint64;\n" + " }\n" + " leaf counter82 {\n" + " type uint64;\n" + " }\n" + " leaf counter83 {\n" + " type uint64;\n" + " }\n" + " leaf counter84 {\n" + " type uint64;\n" + " }\n" + " leaf counter85 {\n" + " type uint64;\n" + " }\n" + " leaf counter86 {\n" + " type uint64;\n" + " }\n" + " leaf counter87 {\n" + " type uint64;\n" + " }\n" + " leaf counter88 {\n" + " type uint64;\n" + " }\n" + " leaf counter89 {\n" + " type uint64;\n" + " }\n" + " leaf counter90 {\n" + " type uint64;\n" + " }\n" + " leaf counter91 {\n" + " type uint64;\n" + " }\n" + " leaf counter92 {\n" + " type uint64;\n" + " }\n" + " leaf counter93 {\n" + " type uint64;\n" + " }\n" + " leaf counter94 {\n" + " type uint64;\n" + " }\n" + " leaf counter95 {\n" + " type uint64;\n" + " }\n" + " leaf counter96 {\n" + " type uint64;\n" + " }\n" + " leaf counter97 {\n" + " type uint64;\n" + " }\n" + " leaf counter98 {\n" + " type uint64;\n" + " }\n" + " leaf counter99 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter100 {\n" + " type uint64;\n" + " }\n" + " leaf counter101 {\n" + " type uint64;\n" + " }\n" + " leaf counter102 {\n" + " type uint64;\n" + " }\n" + " leaf counter103 {\n" + " type uint64;\n" + " }\n" + " leaf counter104 {\n" + " type uint64;\n" + " }\n" + " leaf counter105 {\n" + " type uint64;\n" + " }\n" + " leaf counter106 {\n" + " type uint64;\n" + " }\n" + " leaf counter107 {\n" + " type uint64;\n" + " }\n" + " leaf counter108 {\n" + " type uint64;\n" + " }\n" + " leaf counter109 {\n" + " type uint64;\n" + " }\n" + " leaf counter110 {\n" + " type uint64;\n" + " }\n" + " leaf counter111 {\n" + " type uint64;\n" + " }\n" + " leaf counter112 {\n" + " type uint64;\n" + " }\n" + " leaf counter113 {\n" + " type uint64;\n" + " }\n" + " leaf counter114 {\n" + " type uint64;\n" + " }\n" + " leaf counter115 {\n" + " type uint64;\n" + " }\n" + " leaf counter116 {\n" + " type uint64;\n" + " }\n" + " leaf counter117 {\n" + " type uint64;\n" + " }\n" + " leaf counter118 {\n" + " type uint64;\n" + " }\n" + " leaf counter119 {\n" + " type uint64;\n" + " }\n" + " leaf counter120 {\n" + " type uint64;\n" + " }\n" + " leaf counter121 {\n" + " type uint64;\n" + " }\n" + " leaf counter122 {\n" + " type uint64;\n" + " }\n" + " leaf counter123 {\n" + " type uint64;\n" + " }\n" + " leaf counter124 {\n" + " type uint64;\n" + " }\n" + " leaf counter125 {\n" + " type uint64;\n" + " }\n" + " leaf counter126 {\n" + " type uint64;\n" + " }\n" + " leaf counter127 {\n" + " type uint64;\n" + " }\n" + " leaf counter128 {\n" + " type uint64;\n" + " }\n" + " leaf counter129 {\n" + " type uint64;\n" + " }\n" + " leaf counter130 {\n" + " type uint64;\n" + " }\n" + " leaf counter131 {\n" + " type uint64;\n" + " }\n" + " leaf counter132 {\n" + " type uint64;\n" + " }\n" + " leaf counter133 {\n" + " type uint64;\n" + " }\n" + " leaf counter134 {\n" + " type uint64;\n" + " }\n" + " leaf counter135 {\n" + " type uint64;\n" + " }\n" + " leaf counter136 {\n" + " type uint64;\n" + " }\n" + " leaf counter137 {\n" + " type uint64;\n" + " }\n" + " leaf counter138 {\n" + " type uint64;\n" + " }\n" + " leaf counter139 {\n" + " type uint64;\n" + " }\n" + " leaf counter140 {\n" + " type uint64;\n" + " }\n" + " leaf counter141 {\n" + " type uint64;\n" + " }\n" + " leaf counter142 {\n" + " type uint64;\n" + " }\n" + " leaf counter143 {\n" + " type uint64;\n" + " }\n" + " leaf counter144 {\n" + " type uint64;\n" + " }\n" + " leaf counter145 {\n" + " type uint64;\n" + " }\n" + " leaf counter146 {\n" + " type uint64;\n" + " }\n" + " leaf counter147 {\n" + " type uint64;\n" + " }\n" + " leaf counter148 {\n" + " type uint64;\n" + " }\n" + " leaf counter149 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter150 {\n" + " type uint64;\n" + " }\n" + " leaf counter151 {\n" + " type uint64;\n" + " }\n" + " leaf counter152 {\n" + " type uint64;\n" + " }\n" + " leaf counter153 {\n" + " type uint64;\n" + " }\n" + " leaf counter154 {\n" + " type uint64;\n" + " }\n" + " leaf counter155 {\n" + " type uint64;\n" + " }\n" + " leaf counter156 {\n" + " type uint64;\n" + " }\n" + " leaf counter157 {\n" + " type uint64;\n" + " }\n" + " leaf counter158 {\n" + " type uint64;\n" + " }\n" + " leaf counter159 {\n" + " type uint64;\n" + " }\n" + " leaf counter160 {\n" + " type uint64;\n" + " }\n" + " leaf counter161 {\n" + " type uint64;\n" + " }\n" + " leaf counter162 {\n" + " type uint64;\n" + " }\n" + " leaf counter163 {\n" + " type uint64;\n" + " }\n" + " leaf counter164 {\n" + " type uint64;\n" + " }\n" + " leaf counter165 {\n" + " type uint64;\n" + " }\n" + " leaf counter166 {\n" + " type uint64;\n" + " }\n" + " leaf counter167 {\n" + " type uint64;\n" + " }\n" + " leaf counter168 {\n" + " type uint64;\n" + " }\n" + " leaf counter169 {\n" + " type uint64;\n" + " }\n" + " leaf counter170 {\n" + " type uint64;\n" + " }\n" + " leaf counter171 {\n" + " type uint64;\n" + " }\n" + " leaf counter172 {\n" + " type uint64;\n" + " }\n" + " leaf counter173 {\n" + " type uint64;\n" + " }\n" + " leaf counter174 {\n" + " type uint64;\n" + " }\n" + " leaf counter175 {\n" + " type uint64;\n" + " }\n" + " leaf counter176 {\n" + " type uint64;\n" + " }\n" + " leaf counter177 {\n" + " type uint64;\n" + " }\n" + " leaf counter178 {\n" + " type uint64;\n" + " }\n" + " leaf counter179 {\n" + " type uint64;\n" + " }\n" + " leaf counter180 {\n" + " type uint64;\n" + " }\n" + " leaf counter181 {\n" + " type uint64;\n" + " }\n" + " leaf counter182 {\n" + " type uint64;\n" + " }\n" + " leaf counter183 {\n" + " type uint64;\n" + " }\n" + " leaf counter184 {\n" + " type uint64;\n" + " }\n" + " leaf counter185 {\n" + " type uint64;\n" + " }\n" + " leaf counter186 {\n" + " type uint64;\n" + " }\n" + " leaf counter187 {\n" + " type uint64;\n" + " }\n" + " leaf counter188 {\n" + " type uint64;\n" + " }\n" + " leaf counter189 {\n" + " type uint64;\n" + " }\n" + " leaf counter190 {\n" + " type uint64;\n" + " }\n" + " leaf counter191 {\n" + " type uint64;\n" + " }\n" + " leaf counter192 {\n" + " type uint64;\n" + " }\n" + " leaf counter193 {\n" + " type uint64;\n" + " }\n" + " leaf counter194 {\n" + " type uint64;\n" + " }\n" + " leaf counter195 {\n" + " type uint64;\n" + " }\n" + " leaf counter196 {\n" + " type uint64;\n" + " }\n" + " leaf counter197 {\n" + " type uint64;\n" + " }\n" + " leaf counter198 {\n" + " type uint64;\n" + " }\n" + " leaf counter199 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter200 {\n" + " type uint64;\n" + " }\n" + " leaf counter201 {\n" + " type uint64;\n" + " }\n" + " leaf counter202 {\n" + " type uint64;\n" + " }\n" + " leaf counter203 {\n" + " type uint64;\n" + " }\n" + " leaf counter204 {\n" + " type uint64;\n" + " }\n" + " leaf counter205 {\n" + " type uint64;\n" + " }\n" + " leaf counter206 {\n" + " type uint64;\n" + " }\n" + " leaf counter207 {\n" + " type uint64;\n" + " }\n" + " leaf counter208 {\n" + " type uint64;\n" + " }\n" + " leaf counter209 {\n" + " type uint64;\n" + " }\n" + " leaf counter210 {\n" + " type uint64;\n" + " }\n" + " leaf counter211 {\n" + " type uint64;\n" + " }\n" + " leaf counter212 {\n" + " type uint64;\n" + " }\n" + " leaf counter213 {\n" + " type uint64;\n" + " }\n" + " leaf counter214 {\n" + " type uint64;\n" + " }\n" + " leaf counter215 {\n" + " type uint64;\n" + " }\n" + " leaf counter216 {\n" + " type uint64;\n" + " }\n" + " leaf counter217 {\n" + " type uint64;\n" + " }\n" + " leaf counter218 {\n" + " type uint64;\n" + " }\n" + " leaf counter219 {\n" + " type uint64;\n" + " }\n" + " leaf counter220 {\n" + " type uint64;\n" + " }\n" + " leaf counter221 {\n" + " type uint64;\n" + " }\n" + " leaf counter222 {\n" + " type uint64;\n" + " }\n" + " leaf counter223 {\n" + " type uint64;\n" + " }\n" + " leaf counter224 {\n" + " type uint64;\n" + " }\n" + " leaf counter225 {\n" + " type uint64;\n" + " }\n" + " leaf counter226 {\n" + " type uint64;\n" + " }\n" + " leaf counter227 {\n" + " type uint64;\n" + " }\n" + " leaf counter228 {\n" + " type uint64;\n" + " }\n" + " leaf counter229 {\n" + " type uint64;\n" + " }\n" + " leaf counter230 {\n" + " type uint64;\n" + " }\n" + " leaf counter231 {\n" + " type uint64;\n" + " }\n" + " leaf counter232 {\n" + " type uint64;\n" + " }\n" + " leaf counter233 {\n" + " type uint64;\n" + " }\n" + " leaf counter234 {\n" + " type uint64;\n" + " }\n" + " leaf counter235 {\n" + " type uint64;\n" + " }\n" + " leaf counter236 {\n" + " type uint64;\n" + " }\n" + " leaf counter237 {\n" + " type uint64;\n" + " }\n" + " leaf counter238 {\n" + " type uint64;\n" + " }\n" + " leaf counter239 {\n" + " type uint64;\n" + " }\n" + " leaf counter240 {\n" + " type uint64;\n" + " }\n" + " leaf counter241 {\n" + " type uint64;\n" + " }\n" + " leaf counter242 {\n" + " type uint64;\n" + " }\n" + " leaf counter243 {\n" + " type uint64;\n" + " }\n" + " leaf counter244 {\n" + " type uint64;\n" + " }\n" + " leaf counter245 {\n" + " type uint64;\n" + " }\n" + " leaf counter246 {\n" + " type uint64;\n" + " }\n" + " leaf counter247 {\n" + " type uint64;\n" + " }\n" + " leaf counter248 {\n" + " type uint64;\n" + " }\n" + " leaf counter249 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter250 {\n" + " type uint64;\n" + " }\n" + " leaf counter251 {\n" + " type uint64;\n" + " }\n" + " leaf counter252 {\n" + " type uint64;\n" + " }\n" + " leaf counter253 {\n" + " type uint64;\n" + " }\n" + " leaf counter254 {\n" + " type uint64;\n" + " }\n" + " leaf counter255 {\n" + " type uint64;\n" + " }\n" + " leaf counter256 {\n" + " type uint64;\n" + " }\n" + " leaf counter257 {\n" + " type uint64;\n" + " }\n" + " leaf counter258 {\n" + " type uint64;\n" + " }\n" + " leaf counter259 {\n" + " type uint64;\n" + " }\n" + " leaf counter260 {\n" + " type uint64;\n" + " }\n" + " leaf counter261 {\n" + " type uint64;\n" + " }\n" + " leaf counter262 {\n" + " type uint64;\n" + " }\n" + " leaf counter263 {\n" + " type uint64;\n" + " }\n" + " leaf counter264 {\n" + " type uint64;\n" + " }\n" + " leaf counter265 {\n" + " type uint64;\n" + " }\n" + " leaf counter266 {\n" + " type uint64;\n" + " }\n" + " leaf counter267 {\n" + " type uint64;\n" + " }\n" + " leaf counter268 {\n" + " type uint64;\n" + " }\n" + " leaf counter269 {\n" + " type uint64;\n" + " }\n" + " leaf counter270 {\n" + " type uint64;\n" + " }\n" + " leaf counter271 {\n" + " type uint64;\n" + " }\n" + " leaf counter272 {\n" + " type uint64;\n" + " }\n" + " leaf counter273 {\n" + " type uint64;\n" + " }\n" + " leaf counter274 {\n" + " type uint64;\n" + " }\n" + " leaf counter275 {\n" + " type uint64;\n" + " }\n" + " leaf counter276 {\n" + " type uint64;\n" + " }\n" + " leaf counter277 {\n" + " type uint64;\n" + " }\n" + " leaf counter278 {\n" + " type uint64;\n" + " }\n" + " leaf counter279 {\n" + " type uint64;\n" + " }\n" + " leaf counter280 {\n" + " type uint64;\n" + " }\n" + " leaf counter281 {\n" + " type uint64;\n" + " }\n" + " leaf counter282 {\n" + " type uint64;\n" + " }\n" + " leaf counter283 {\n" + " type uint64;\n" + " }\n" + " leaf counter284 {\n" + " type uint64;\n" + " }\n" + " leaf counter285 {\n" + " type uint64;\n" + " }\n" + " leaf counter286 {\n" + " type uint64;\n" + " }\n" + " leaf counter287 {\n" + " type uint64;\n" + " }\n" + " leaf counter288 {\n" + " type uint64;\n" + " }\n" + " leaf counter289 {\n" + " type uint64;\n" + " }\n" + " leaf counter290 {\n" + " type uint64;\n" + " }\n" + " leaf counter291 {\n" + " type uint64;\n" + " }\n" + " leaf counter292 {\n" + " type uint64;\n" + " }\n" + " leaf counter293 {\n" + " type uint64;\n" + " }\n" + " leaf counter294 {\n" + " type uint64;\n" + " }\n" + " leaf counter295 {\n" + " type uint64;\n" + " }\n" + " leaf counter296 {\n" + " type uint64;\n" + " }\n" + " leaf counter297 {\n" + " type uint64;\n" + " }\n" + " leaf counter298 {\n" + " type uint64;\n" + " }\n" + " leaf counter299 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter300 {\n" + " type uint64;\n" + " }\n" + " leaf counter301 {\n" + " type uint64;\n" + " }\n" + " leaf counter302 {\n" + " type uint64;\n" + " }\n" + " leaf counter303 {\n" + " type uint64;\n" + " }\n" + " leaf counter304 {\n" + " type uint64;\n" + " }\n" + " leaf counter305 {\n" + " type uint64;\n" + " }\n" + " leaf counter306 {\n" + " type uint64;\n" + " }\n" + " leaf counter307 {\n" + " type uint64;\n" + " }\n" + " leaf counter308 {\n" + " type uint64;\n" + " }\n" + " leaf counter309 {\n" + " type uint64;\n" + " }\n" + " leaf counter310 {\n" + " type uint64;\n" + " }\n" + " leaf counter311 {\n" + " type uint64;\n" + " }\n" + " leaf counter312 {\n" + " type uint64;\n" + " }\n" + " leaf counter313 {\n" + " type uint64;\n" + " }\n" + " leaf counter314 {\n" + " type uint64;\n" + " }\n" + " leaf counter315 {\n" + " type uint64;\n" + " }\n" + " leaf counter316 {\n" + " type uint64;\n" + " }\n" + " leaf counter317 {\n" + " type uint64;\n" + " }\n" + " leaf counter318 {\n" + " type uint64;\n" + " }\n" + " leaf counter319 {\n" + " type uint64;\n" + " }\n" + " leaf counter320 {\n" + " type uint64;\n" + " }\n" + " leaf counter321 {\n" + " type uint64;\n" + " }\n" + " leaf counter322 {\n" + " type uint64;\n" + " }\n" + " leaf counter323 {\n" + " type uint64;\n" + " }\n" + " leaf counter324 {\n" + " type uint64;\n" + " }\n" + " leaf counter325 {\n" + " type uint64;\n" + " }\n" + " leaf counter326 {\n" + " type uint64;\n" + " }\n" + " leaf counter327 {\n" + " type uint64;\n" + " }\n" + " leaf counter328 {\n" + " type uint64;\n" + " }\n" + " leaf counter329 {\n" + " type uint64;\n" + " }\n" + " leaf counter330 {\n" + " type uint64;\n" + " }\n" + " leaf counter331 {\n" + " type uint64;\n" + " }\n" + " leaf counter332 {\n" + " type uint64;\n" + " }\n" + " leaf counter333 {\n" + " type uint64;\n" + " }\n" + " leaf counter334 {\n" + " type uint64;\n" + " }\n" + " leaf counter335 {\n" + " type uint64;\n" + " }\n" + " leaf counter336 {\n" + " type uint64;\n" + " }\n" + " leaf counter337 {\n" + " type uint64;\n" + " }\n" + " leaf counter338 {\n" + " type uint64;\n" + " }\n" + " leaf counter339 {\n" + " type uint64;\n" + " }\n" + " leaf counter340 {\n" + " type uint64;\n" + " }\n" + " leaf counter341 {\n" + " type uint64;\n" + " }\n" + " leaf counter342 {\n" + " type uint64;\n" + " }\n" + " leaf counter343 {\n" + " type uint64;\n" + " }\n" + " leaf counter344 {\n" + " type uint64;\n" + " }\n" + " leaf counter345 {\n" + " type uint64;\n" + " }\n" + " leaf counter346 {\n" + " type uint64;\n" + " }\n" + " leaf counter347 {\n" + " type uint64;\n" + " }\n" + " leaf counter348 {\n" + " type uint64;\n" + " }\n" + " leaf counter349 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter350 {\n" + " type uint64;\n" + " }\n" + " leaf counter351 {\n" + " type uint64;\n" + " }\n" + " leaf counter352 {\n" + " type uint64;\n" + " }\n" + " leaf counter353 {\n" + " type uint64;\n" + " }\n" + " leaf counter354 {\n" + " type uint64;\n" + " }\n" + " leaf counter355 {\n" + " type uint64;\n" + " }\n" + " leaf counter356 {\n" + " type uint64;\n" + " }\n" + " leaf counter357 {\n" + " type uint64;\n" + " }\n" + " leaf counter358 {\n" + " type uint64;\n" + " }\n" + " leaf counter359 {\n" + " type uint64;\n" + " }\n" + " leaf counter360 {\n" + " type uint64;\n" + " }\n" + " leaf counter361 {\n" + " type uint64;\n" + " }\n" + " leaf counter362 {\n" + " type uint64;\n" + " }\n" + " leaf counter363 {\n" + " type uint64;\n" + " }\n" + " leaf counter364 {\n" + " type uint64;\n" + " }\n" + " leaf counter365 {\n" + " type uint64;\n" + " }\n" + " leaf counter366 {\n" + " type uint64;\n" + " }\n" + " leaf counter367 {\n" + " type uint64;\n" + " }\n" + " leaf counter368 {\n" + " type uint64;\n" + " }\n" + " leaf counter369 {\n" + " type uint64;\n" + " }\n" + " leaf counter370 {\n" + " type uint64;\n" + " }\n" + " leaf counter371 {\n" + " type uint64;\n" + " }\n" + " leaf counter372 {\n" + " type uint64;\n" + " }\n" + " leaf counter373 {\n" + " type uint64;\n" + " }\n" + " leaf counter374 {\n" + " type uint64;\n" + " }\n" + " leaf counter375 {\n" + " type uint64;\n" + " }\n" + " leaf counter376 {\n" + " type uint64;\n" + " }\n" + " leaf counter377 {\n" + " type uint64;\n" + " }\n" + " leaf counter378 {\n" + " type uint64;\n" + " }\n" + " leaf counter379 {\n" + " type uint64;\n" + " }\n" + " leaf counter380 {\n" + " type uint64;\n" + " }\n" + " leaf counter381 {\n" + " type uint64;\n" + " }\n" + " leaf counter382 {\n" + " type uint64;\n" + " }\n" + " leaf counter383 {\n" + " type uint64;\n" + " }\n" + " leaf counter384 {\n" + " type uint64;\n" + " }\n" + " leaf counter385 {\n" + " type uint64;\n" + " }\n" + " leaf counter386 {\n" + " type uint64;\n" + " }\n" + " leaf counter387 {\n" + " type uint64;\n" + " }\n" + " leaf counter388 {\n" + " type uint64;\n" + " }\n" + " leaf counter389 {\n" + " type uint64;\n" + " }\n" + " leaf counter390 {\n" + " type uint64;\n" + " }\n" + " leaf counter391 {\n" + " type uint64;\n" + " }\n" + " leaf counter392 {\n" + " type uint64;\n" + " }\n" + " leaf counter393 {\n" + " type uint64;\n" + " }\n" + " leaf counter394 {\n" + " type uint64;\n" + " }\n" + " leaf counter395 {\n" + " type uint64;\n" + " }\n" + " leaf counter396 {\n" + " type uint64;\n" + " }\n" + " leaf counter397 {\n" + " type uint64;\n" + " }\n" + " leaf counter398 {\n" + " type uint64;\n" + " }\n" + " leaf counter399 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter400 {\n" + " type uint64;\n" + " }\n" + " leaf counter401 {\n" + " type uint64;\n" + " }\n" + " leaf counter402 {\n" + " type uint64;\n" + " }\n" + " leaf counter403 {\n" + " type uint64;\n" + " }\n" + " leaf counter404 {\n" + " type uint64;\n" + " }\n" + " leaf counter405 {\n" + " type uint64;\n" + " }\n" + " leaf counter406 {\n" + " type uint64;\n" + " }\n" + " leaf counter407 {\n" + " type uint64;\n" + " }\n" + " leaf counter408 {\n" + " type uint64;\n" + " }\n" + " leaf counter409 {\n" + " type uint64;\n" + " }\n" + " leaf counter410 {\n" + " type uint64;\n" + " }\n" + " leaf counter411 {\n" + " type uint64;\n" + " }\n" + " leaf counter412 {\n" + " type uint64;\n" + " }\n" + " leaf counter413 {\n" + " type uint64;\n" + " }\n" + " leaf counter414 {\n" + " type uint64;\n" + " }\n" + " leaf counter415 {\n" + " type uint64;\n" + " }\n" + " leaf counter416 {\n" + " type uint64;\n" + " }\n" + " leaf counter417 {\n" + " type uint64;\n" + " }\n" + " leaf counter418 {\n" + " type uint64;\n" + " }\n" + " leaf counter419 {\n" + " type uint64;\n" + " }\n" + " leaf counter420 {\n" + " type uint64;\n" + " }\n" + " leaf counter421 {\n" + " type uint64;\n" + " }\n" + " leaf counter422 {\n" + " type uint64;\n" + " }\n" + " leaf counter423 {\n" + " type uint64;\n" + " }\n" + " leaf counter424 {\n" + " type uint64;\n" + " }\n" + " leaf counter425 {\n" + " type uint64;\n" + " }\n" + " leaf counter426 {\n" + " type uint64;\n" + " }\n" + " leaf counter427 {\n" + " type uint64;\n" + " }\n" + " leaf counter428 {\n" + " type uint64;\n" + " }\n" + " leaf counter429 {\n" + " type uint64;\n" + " }\n" + " leaf counter430 {\n" + " type uint64;\n" + " }\n" + " leaf counter431 {\n" + " type uint64;\n" + " }\n" + " leaf counter432 {\n" + " type uint64;\n" + " }\n" + " leaf counter433 {\n" + " type uint64;\n" + " }\n" + " leaf counter434 {\n" + " type uint64;\n" + " }\n" + " leaf counter435 {\n" + " type uint64;\n" + " }\n" + " leaf counter436 {\n" + " type uint64;\n" + " }\n" + " leaf counter437 {\n" + " type uint64;\n" + " }\n" + " leaf counter438 {\n" + " type uint64;\n" + " }\n" + " leaf counter439 {\n" + " type uint64;\n" + " }\n" + " leaf counter440 {\n" + " type uint64;\n" + " }\n" + " leaf counter441 {\n" + " type uint64;\n" + " }\n" + " leaf counter442 {\n" + " type uint64;\n" + " }\n" + " leaf counter443 {\n" + " type uint64;\n" + " }\n" + " leaf counter444 {\n" + " type uint64;\n" + " }\n" + " leaf counter445 {\n" + " type uint64;\n" + " }\n" + " leaf counter446 {\n" + " type uint64;\n" + " }\n" + " leaf counter447 {\n" + " type uint64;\n" + " }\n" + " leaf counter448 {\n" + " type uint64;\n" + " }\n" + " leaf counter449 {\n" + " type uint64;\n" + " }\n"); + strcat(counters_yang, + " leaf counter450 {\n" + " type uint64;\n" + " }\n" + " leaf counter451 {\n" + " type uint64;\n" + " }\n" + " leaf counter452 {\n" + " type uint64;\n" + " }\n" + " leaf counter453 {\n" + " type uint64;\n" + " }\n" + " leaf counter454 {\n" + " type uint64;\n" + " }\n" + " leaf counter455 {\n" + " type uint64;\n" + " }\n" + " leaf counter456 {\n" + " type uint64;\n" + " }\n" + " leaf counter457 {\n" + " type uint64;\n" + " }\n" + " leaf counter458 {\n" + " type uint64;\n" + " }\n" + " leaf counter459 {\n" + " type uint64;\n" + " }\n" + " leaf counter460 {\n" + " type uint64;\n" + " }\n" + " leaf counter461 {\n" + " type uint64;\n" + " }\n" + " leaf counter462 {\n" + " type uint64;\n" + " }\n" + " leaf counter463 {\n" + " type uint64;\n" + " }\n" + " leaf counter464 {\n" + " type uint64;\n" + " }\n" + " leaf counter465 {\n" + " type uint64;\n" + " }\n" + " leaf counter466 {\n" + " type uint64;\n" + " }\n" + " leaf counter467 {\n" + " type uint64;\n" + " }\n" + " leaf counter468 {\n" + " type uint64;\n" + " }\n" + " leaf counter469 {\n" + " type uint64;\n" + " }\n" + " leaf counter470 {\n" + " type uint64;\n" + " }\n" + " leaf counter471 {\n" + " type uint64;\n" + " }\n" + " leaf counter472 {\n" + " type uint64;\n" + " }\n" + " leaf counter473 {\n" + " type uint64;\n" + " }\n" + " leaf counter474 {\n" + " type uint64;\n" + " }\n" + " leaf counter475 {\n" + " type uint64;\n" + " }\n" + " leaf counter476 {\n" + " type uint64;\n" + " }\n" + " leaf counter477 {\n" + " type uint64;\n" + " }\n" + " leaf counter478 {\n" + " type uint64;\n" + " }\n" + " leaf counter479 {\n" + " type uint64;\n" + " }\n" + " leaf counter480 {\n" + " type uint64;\n" + " }\n" + " leaf counter481 {\n" + " type uint64;\n" + " }\n" + " leaf counter482 {\n" + " type uint64;\n" + " }\n" + " leaf counter483 {\n" + " type uint64;\n" + " }\n" + " leaf counter484 {\n" + " type uint64;\n" + " }\n" + " leaf counter485 {\n" + " type uint64;\n" + " }\n" + " leaf counter486 {\n" + " type uint64;\n" + " }\n" + " leaf counter487 {\n" + " type uint64;\n" + " }\n" + " leaf counter488 {\n" + " type uint64;\n" + " }\n" + " leaf counter489 {\n" + " type uint64;\n" + " }\n" + " leaf counter490 {\n" + " type uint64;\n" + " }\n" + " leaf counter491 {\n" + " type uint64;\n" + " }\n" + " leaf counter492 {\n" + " type uint64;\n" + " }\n" + " leaf counter493 {\n" + " type uint64;\n" + " }\n" + " leaf counter494 {\n" + " type uint64;\n" + " }\n" + " leaf counter495 {\n" + " type uint64;\n" + " }\n" + " leaf counter496 {\n" + " type uint64;\n" + " }\n" + " leaf counter497 {\n" + " type uint64;\n" + " }\n" + " leaf counter498 {\n" + " type uint64;\n" + " }\n" + " leaf counter499 {\n" + " type uint64;\n" + " }\n" + " }\n" + "}\n"); + + data_xml = malloc(16384); + strcpy(data_xml, + "\n"); + strcat(data_xml, + " 1\n" + " 2\n" + " 3\n" + " 4\n" + " 5\n" + " 6\n" + " 7\n" + " 8\n" + " 9\n" + " 10\n" + " 11\n" + " 12\n" + " 13\n" + " 14\n" + " 15\n" + " 16\n" + " 17\n" + " 18\n" + " 19\n" + " 20\n" + " 21\n" + " 22\n" + " 23\n" + " 24\n" + " 25\n" + " 26\n" + " 27\n" + " 28\n" + " 29\n" + " 30\n" + " 31\n" + " 32\n" + " 33\n" + " 34\n" + " 35\n" + " 36\n" + " 37\n" + " 38\n" + " 39\n" + " 40\n" + " 41\n" + " 42\n" + " 43\n" + " 44\n" + " 45\n" + " 46\n" + " 47\n" + " 48\n" + " 49\n" + " 50\n" + " 51\n" + " 52\n" + " 53\n" + " 54\n" + " 55\n" + " 56\n" + " 57\n" + " 58\n" + " 59\n" + " 60\n" + " 61\n" + " 62\n" + " 63\n" + " 64\n" + " 65\n" + " 66\n" + " 67\n" + " 68\n" + " 69\n" + " 70\n" + " 71\n" + " 72\n" + " 73\n" + " 74\n" + " 75\n" + " 76\n" + " 77\n" + " 78\n" + " 79\n" + " 80\n" + " 81\n" + " 82\n" + " 83\n" + " 84\n" + " 85\n" + " 86\n" + " 87\n" + " 88\n" + " 89\n" + " 90\n" + " 91\n" + " 92\n" + " 93\n" + " 94\n" + " 95\n" + " 96\n" + " 97\n" + " 98\n" + " 99\n"); + strcat(data_xml, + " 100\n" + " 101\n" + " 102\n" + " 103\n" + " 104\n" + " 105\n" + " 106\n" + " 107\n" + " 108\n" + " 109\n" + " 110\n" + " 111\n" + " 112\n" + " 113\n" + " 114\n" + " 115\n" + " 116\n" + " 117\n" + " 118\n" + " 119\n" + " 120\n" + " 121\n" + " 122\n" + " 123\n" + " 124\n" + " 125\n" + " 126\n" + " 127\n" + " 128\n" + " 129\n" + " 130\n" + " 131\n" + " 132\n" + " 133\n" + " 134\n" + " 135\n" + " 136\n" + " 137\n" + " 138\n" + " 139\n" + " 140\n" + " 141\n" + " 142\n" + " 143\n" + " 144\n" + " 145\n" + " 146\n" + " 147\n" + " 148\n" + " 149\n" + " 150\n" + " 151\n" + " 152\n" + " 153\n" + " 154\n" + " 155\n" + " 156\n" + " 157\n" + " 158\n" + " 159\n" + " 160\n" + " 161\n" + " 162\n" + " 163\n" + " 164\n" + " 165\n" + " 166\n" + " 167\n" + " 168\n" + " 169\n" + " 170\n" + " 171\n" + " 172\n" + " 173\n" + " 174\n" + " 175\n" + " 176\n" + " 177\n" + " 178\n" + " 179\n" + " 180\n" + " 181\n" + " 182\n" + " 183\n" + " 184\n" + " 185\n" + " 186\n" + " 187\n" + " 188\n" + " 189\n" + " 190\n" + " 191\n" + " 192\n" + " 193\n" + " 194\n" + " 195\n" + " 196\n" + " 197\n" + " 198\n" + " 199\n"); + strcat(data_xml, + " 200\n" + " 201\n" + " 202\n" + " 203\n" + " 204\n" + " 205\n" + " 206\n" + " 207\n" + " 208\n" + " 209\n" + " 210\n" + " 211\n" + " 212\n" + " 213\n" + " 214\n" + " 215\n" + " 216\n" + " 217\n" + " 218\n" + " 219\n" + " 220\n" + " 221\n" + " 222\n" + " 223\n" + " 224\n" + " 225\n" + " 226\n" + " 227\n" + " 228\n" + " 229\n" + " 230\n" + " 231\n" + " 232\n" + " 233\n" + " 234\n" + " 235\n" + " 236\n" + " 237\n" + " 238\n" + " 239\n" + " 240\n" + " 241\n" + " 242\n" + " 243\n" + " 244\n" + " 245\n" + " 246\n" + " 247\n" + " 248\n" + " 249\n" + " 250\n" + " 251\n" + " 252\n" + " 253\n" + " 254\n" + " 255\n" + " 256\n" + " 257\n" + " 258\n" + " 259\n" + " 260\n" + " 261\n" + " 262\n" + " 263\n" + " 264\n" + " 265\n" + " 266\n" + " 267\n" + " 268\n" + " 269\n" + " 270\n" + " 271\n" + " 272\n" + " 273\n" + " 274\n" + " 275\n" + " 276\n" + " 277\n" + " 278\n" + " 279\n" + " 280\n" + " 281\n" + " 282\n" + " 283\n" + " 284\n" + " 285\n" + " 286\n" + " 287\n" + " 288\n" + " 289\n" + " 290\n" + " 291\n" + " 292\n" + " 293\n" + " 294\n" + " 295\n" + " 296\n" + " 297\n" + " 298\n" + " 299\n"); + strcat(data_xml, + " 300\n" + " 301\n" + " 302\n" + " 303\n" + " 304\n" + " 305\n" + " 306\n" + " 307\n" + " 308\n" + " 309\n" + " 310\n" + " 311\n" + " 312\n" + " 313\n" + " 314\n" + " 315\n" + " 316\n" + " 317\n" + " 318\n" + " 319\n" + " 320\n" + " 321\n" + " 322\n" + " 323\n" + " 324\n" + " 325\n" + " 326\n" + " 327\n" + " 328\n" + " 329\n" + " 330\n" + " 331\n" + " 332\n" + " 333\n" + " 334\n" + " 335\n" + " 336\n" + " 337\n" + " 338\n" + " 339\n" + " 340\n" + " 341\n" + " 342\n" + " 343\n" + " 344\n" + " 345\n" + " 346\n" + " 347\n" + " 348\n" + " 349\n" + " 350\n" + " 351\n" + " 352\n" + " 353\n" + " 354\n" + " 355\n" + " 356\n" + " 357\n" + " 358\n" + " 359\n" + " 360\n" + " 361\n" + " 362\n" + " 363\n" + " 364\n" + " 365\n" + " 366\n" + " 367\n" + " 368\n" + " 369\n" + " 370\n" + " 371\n" + " 372\n" + " 373\n" + " 374\n" + " 375\n" + " 376\n" + " 377\n" + " 378\n" + " 379\n" + " 380\n" + " 381\n" + " 382\n" + " 383\n" + " 384\n" + " 385\n" + " 386\n" + " 387\n" + " 388\n" + " 389\n" + " 390\n" + " 391\n" + " 392\n" + " 393\n" + " 394\n" + " 395\n" + " 396\n" + " 397\n" + " 398\n" + " 399\n"); + strcat(data_xml, + " 400\n" + " 401\n" + " 402\n" + " 403\n" + " 404\n" + " 405\n" + " 406\n" + " 407\n" + " 408\n" + " 409\n" + " 410\n" + " 411\n" + " 412\n" + " 413\n" + " 414\n" + " 415\n" + " 416\n" + " 417\n" + " 418\n" + " 419\n" + " 420\n" + " 421\n" + " 422\n" + " 423\n" + " 424\n" + " 425\n" + " 426\n" + " 427\n" + " 428\n" + " 429\n" + " 430\n" + " 431\n" + " 432\n" + " 433\n" + " 434\n" + " 435\n" + " 436\n" + " 437\n" + " 438\n" + " 439\n" + " 440\n" + " 441\n" + " 442\n" + " 443\n" + " 444\n" + " 445\n" + " 446\n" + " 447\n" + " 448\n" + " 449\n" + " 450\n" + " 451\n" + " 452\n" + " 453\n" + " 454\n" + " 455\n" + " 456\n" + " 457\n" + " 458\n" + " 459\n" + " 460\n" + " 461\n" + " 462\n" + " 463\n" + " 464\n" + " 465\n" + " 466\n" + " 467\n" + " 468\n" + " 469\n" + " 470\n" + " 471\n" + " 472\n" + " 473\n" + " 474\n" + " 475\n" + " 476\n" + " 477\n" + " 478\n" + " 479\n" + " 480\n" + " 481\n" + " 482\n" + " 483\n" + " 484\n" + " 485\n" + " 486\n" + " 487\n" + " 488\n" + " 489\n" + " 490\n" + " 491\n" + " 492\n" + " 493\n" + " 494\n" + " 495\n" + " 496\n" + " 497\n" + " 498\n" + " 499\n" + "\n"); + + UTEST_ADD_MODULE(counters_yang, LYS_IN_YANG, NULL, NULL); + + check_print_parse(state, data_xml); + + free(counters_yang); + free(data_xml); +} + +#if 0 + +static void +test_types(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "types", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/types.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_annotations(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/annotations.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_similar_annot_names(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/similar-annot-names.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_many_child_annot(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/many-childs-annot.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_union(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "union", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/union.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_union2(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "statements", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/union2.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_collisions(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/collisions.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_anydata(void **state) +{ + struct state *st = (*state); + const struct lys_module *mod; + int ret; + const char *test_anydata = + "module test-anydata {" + " namespace \"urn:test-anydata\";" + " prefix ya;" + "" + " container cont {" + " anydata ntf;" + " }" + "}"; + + assert_non_null(ly_ctx_load_module(st->ctx, "ietf-netconf-notifications", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/ietf-netconf-notifications.json", LYD_JSON, LYD_OPT_NOTIF | LYD_OPT_TRUSTED, NULL); + assert_ptr_not_equal(st->dt1, NULL); + + / *get notification in LYB format to set as anydata content * / + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + lyd_free_withsiblings(st->dt1); + st->dt1 = NULL; + + / *now comes the real test, test anydata * / + mod = lys_parse_mem(st->ctx, test_anydata, LYS_YANG); + assert_non_null(mod); + + st->dt1 = lyd_new(NULL, mod, "cont"); + assert_non_null(st->dt1); + + assert_non_null(lyd_new_anydata(st->dt1, NULL, "ntf", st->mem, LYD_ANYDATA_LYBD)); + st->mem = NULL; + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + ret = lyd_validate(&st->dt1, LYD_OPT_CONFIG, NULL); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); + + /* and also test the embedded notification itself */ + free(st->mem); + ret = lyd_lyb_data_length(((struct lyd_node_anydata *)st->dt1->child)->value.mem); + st->mem = malloc(ret); + memcpy(st->mem, ((struct lyd_node_anydata *)st->dt1->child)->value.mem, ret); + + lyd_free_withsiblings(st->dt2); + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_NOTIF | LYD_OPT_STRICT | LYD_OPT_NOEXTDEPS, NULL); + assert_ptr_not_equal(st->dt2, NULL); + + /* parse the JSON again for this comparison */ + lyd_free_withsiblings(st->dt1); + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/ietf-netconf-notifications.json", LYD_JSON, LYD_OPT_NOTIF | LYD_OPT_TRUSTED, NULL); + assert_ptr_not_equal(st->dt1, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_submodule_feature(void **state) +{ + struct state *st = (*state); + const struct lys_module *mod; + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + mod = ly_ctx_load_module(st->ctx, "feature-submodule-main", NULL); + assert_non_null(mod); + assert_int_equal(lys_features_enable(mod, "test-submodule-feature"), 0); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/test-submodule-feature.json", LYD_JSON, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_coliding_augments(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "augment-target", NULL)); + assert_non_null(ly_ctx_load_module(st->ctx, "augment0", NULL)); + assert_non_null(ly_ctx_load_module(st->ctx, "augment1", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/augment.xml", LYD_XML, LYD_OPT_CONFIG); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +static void +test_leafrefs(void **state) +{ + struct state *st = (*state); + int ret; + + ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files"); + assert_non_null(ly_ctx_load_module(st->ctx, "leafrefs2", NULL)); + + st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/leafrefs2.json", LYD_JSON, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt1, NULL); + + ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS); + assert_int_equal(ret, 0); + + st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT); + assert_ptr_not_equal(st->dt2, NULL); + + check_data_tree(st->dt1, st->dt2); +} + +#endif + +int +main(void) +{ + const struct CMUnitTest tests[] = { + UTEST(tests_leaflist), + UTEST(tests_list), + UTEST(tests_any), + UTEST(test_ietf_interfaces, setup), + UTEST(test_origin, setup), + UTEST(test_statements, setup), + UTEST(test_opaq, setup), + UTEST(test_collisions, setup), +#if 0 + cmocka_unit_test_setup_teardown(test_types, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_annotations, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_similar_annot_names, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_many_child_annot, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_union, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_union2, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_collisions, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_anydata, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_submodule_feature, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_coliding_augments, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_leafrefs, setup_f, teardown_f), +#endif + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/utests/data/test_merge.c b/tests/utests/data/test_merge.c new file mode 100644 index 0000000..3e7b772 --- /dev/null +++ b/tests/utests/data/test_merge.c @@ -0,0 +1,756 @@ +/** + * @file test_merge.c + * @author Michal Vasko + * @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 = + "\n" + " \n" + " yang\n" + " 2016-02-11\n" + " implement\n" + " \n" + "\n"; + const char *data[] = { + "\n" + " \n" + " ietf-yang-library\n" + " 2016-02-01\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf-acm\n" + " 2012-02-22\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf\n" + " 2011-06-01\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf-monitoring\n" + " 2010-10-04\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf-with-defaults\n" + " 2011-06-01\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " yang\n" + " 2016-02-11\n" + " urn:ietf:params:xml:ns:yang:1\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-yang-library\n" + " 2016-02-01\n" + " urn:ietf:params:xml:ns:yang:ietf-yang-library\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf-acm\n" + " 2012-02-22\n" + " urn:ietf:params:xml:ns:yang:ietf-netconf-acm\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf\n" + " 2011-06-01\n" + " urn:ietf:params:xml:ns:netconf:base:1.0\n" + " writable-running\n" + " candidate\n" + " rollback-on-error\n" + " validate\n" + " startup\n" + " xpath\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf-monitoring\n" + " 2010-10-04\n" + " urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\n" + " implement\n" + " \n" + "\n", + "\n" + " \n" + " ietf-netconf-with-defaults\n" + " 2011-06-01\n" + " urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\n" + " implement\n" + " \n" + "\n" + }; + const char *output_template = + "\n" + " \n" + " yang\n" + " 2016-02-11\n" + " urn:ietf:params:xml:ns:yang:1\n" + " implement\n" + " \n" + " \n" + " ietf-yang-library\n" + " 2016-02-01\n" + " urn:ietf:params:xml:ns:yang:ietf-yang-library\n" + " implement\n" + " \n" + " \n" + " ietf-netconf-acm\n" + " 2012-02-22\n" + " urn:ietf:params:xml:ns:yang:ietf-netconf-acm\n" + " implement\n" + " \n" + " \n" + " ietf-netconf\n" + " 2011-06-01\n" + " urn:ietf:params:xml:ns:netconf:base:1.0\n" + " writable-running\n" + " candidate\n" + " rollback-on-error\n" + " validate\n" + " startup\n" + " xpath\n" + " implement\n" + " \n" + " \n" + " ietf-netconf-monitoring\n" + " 2010-10-04\n" + " urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\n" + " implement\n" + " \n" + " \n" + " ietf-netconf-with-defaults\n" + " 2011-06-01\n" + " urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\n" + " implement\n" + " \n" + "\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 = " block "; + const char *src = " aa bb "; + const char *result = "aabb"; + 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 = " aaa "; + const char *src = " bbb "; + const char *result = "aaabbb"; + 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 = + "\n" + " \n" + " 1\n" + " a\n" + " true\n" + " \n" + "\n"; + const char *src = + "\n" + " \n" + " 1\n" + " b\n" + " \n" + "\n"; + const char *result = + "\n" + " \n" + " 1\n" + " b\n" + " true\n" + " \n" + "\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 = + "\n" + " \n" + " 1\n" + " a\n" + " \n" + " val\n" + " \n" + " \n" + "\n"; + const char *src = + "\n" + " \n" + " 1\n" + " b\n" + " \n" + "\n"; + const char *result = + "\n" + " \n" + " 1\n" + " b\n" + " \n" + " val\n" + " \n" + " \n" + "\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 = + "\n" + " \n" + " 1\n" + " b\n" + " \n" + " \n" + " 1\n" + " a\n" + " \n" + " val\n" + " \n" + " \n" + "\n"; + const char *src = + "\n" + " \n" + " 1\n" + " b\n" + " \n" + " \n" + " 2\n" + " a\n" + " \n" + "\n"; + const char *result = + "\n" + " \n" + " 1\n" + " b\n" + " \n" + " \n" + " 1\n" + " a\n" + " \n" + " val\n" + " \n" + " \n" + " \n" + " 2\n" + " a\n" + " \n" + "\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 = + "\n" + " a\n" + " b\n" + " c\n" + " d\n" + " a\n" + " b\n" + " c\n" + " d\n" + "\n"; + const char *src = + "\n" + " d\n" + " c\n" + " b\n" + " a\n" + " a\n" + " a\n" + " a\n" + " f\n" + " f\n" + "\n"; + const char *result = + "\n" + " a\n" + " b\n" + " c\n" + " d\n" + " a\n" + " b\n" + " c\n" + " d\n" + " a\n" + " a\n" + " f\n" + " f\n" + "\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 = + "\n" + " \n" + " 1\n" + " \n" + "\n"; + const char *src = + "\n" + " 1\n" + "\n"; + const char *result = + "\n" + " 1\n" + "\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 = "a" + "ba"; + const char *src = "ca" + "a*"; + const char *res = "a*" + "ba" + "ca"; + 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); +} diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c new file mode 100644 index 0000000..7642960 --- /dev/null +++ b/tests/utests/data/test_new.c @@ -0,0 +1,446 @@ +/** + * @file test_new.c + * @author: Michal Vasko + * @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" + " 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 \"]\" (\"]\").", "Schema location \"/a:l1\"."); + + 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.", "Schema location \"/a:l1\"."); + + 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.", "Schema location \"/a:l1\"."); + + 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); + + 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); + + /* 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']\".", "Schema location \"/a:foo\"."); + + assert_int_equal(lyd_new_term(NULL, mod, "c", "value", 0, &node), LY_ENOTFOUND); + CHECK_LOG_CTX("Term node \"c\" not found.", NULL); + + assert_int_equal(lyd_new_term(NULL, mod, "foo", "256", 0, &node), LY_SUCCESS); + lyd_free_tree(node); + + /* 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); + + 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); + + /* anydata */ + assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS); + lyd_free_tree(node); + assert_int_equal(lyd_new_any(NULL, mod, "any", "val", 0, 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.", "Schema location \"/a:l2\"."); + + 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", 1, &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\".", "Schema location \"/a:l1\"."); + + 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.", "Schema location \"/a:foo\"."); + + 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); + + 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, + "\n" + " \n" + " val1\n" + " \n" + " \n" + " val2\n" + " \n" + " \n" + " val3\n" + " \n" + " \n" + " val4\n" + " \n" + " \n" + " val5\n" + " \n" + " \n" + " val6\n" + " \n" + "\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); + + 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); + + lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS); + assert_string_equal(str, + "val\n" + "val2\n" + "val3\n"); + free(str); + lyd_free_siblings(root); + + /* anydata */ + ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", "val", 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, + "\n" + " val\n" + "\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); +} + +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); +} diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c new file mode 100644 index 0000000..d341e31 --- /dev/null +++ b/tests/utests/data/test_parser_json.c @@ -0,0 +1,793 @@ +/* + * @file test_parser_json.c + * @author: Radek Krejci + * @brief unit tests for functions from parser_xml.c + * + * Copyright (c) 2019 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; }" + "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) \ + 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);\ + 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\".", "Data location \"/@a:foo\", line number 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.", "Data location \"/@a:foo\", line number 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\".", + "Schema location \"/a:foo\", line number 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\".", + "Data location \"/a:l1[a='val-a'][b='val-b'][c='1']/cont/e\", line number 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)); +} + +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_null(ll->meta); + + 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, 1, "hint", 1, 1, INT8, "1", 1); + CHECK_LYD_META(ll->meta->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.", "Data location \"/@a:ll1\", line number 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.", "Schema location \"/a:ll1\", line number 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.", + "Data location \"/@a:ll1\", line number 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); +} + +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\".", + "Data location \"/a:l1[b='b'][c='1']\", line number 1."); + + PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"a\" : \"a\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "List instance is missing its key \"b\".", "Data location \"/a:l1[a='a']\", line number 1."); + + PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"b\" : \"b\", \"a\" : \"a\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "List instance is missing its key \"c\".", "Data location \"/a:l1[a='a'][b='b']\", line number 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\".", + "Data location \"/a:l1[a='a'][b='b'][c='1'][c='1']/c\", line number 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); + + 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); + + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, + "{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1}]}"); + 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); +} + +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 \"\".", "Schema location \"/a:foo3\", line number 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); + + /* 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\".", + "Data location \"/a:l1[a='val_a'][b='val_b']\", line number 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\".", + "Data location \"/a:l1[a='val_a'][b='val_b']/c\", line number 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\".", "Data location \"/@a:foo\"."); + + /* empty name */ + PARSER_CHECK_ERROR("{\"@a:foo\":{\"\":0}}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "A JSON object member name cannot be a zero-length string.", "Line number 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; + 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" + " element is generated, the server will stop\n" + "processing the operation and restore the\n" + "specified configuration to its complete state at\n" + "the start of this 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); + + /* wrong namespace, element name, whatever... */ + /* TODO */ +} + +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 */ +} + +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), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c new file mode 100644 index 0000000..7defd9c --- /dev/null +++ b/tests/utests/data/test_parser_xml.c @@ -0,0 +1,836 @@ +/** + * @file test_parser_xml.c + * @author Radek Krejci + * @author Michal Vasko + * @brief unit tests for functions from parser_xml.c + * + * 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 "context.h" +#include "in.h" +#include "out.h" +#include "parser_data.h" +#include "printer_data.h" +#include "tree_data_internal.h" +#include "tree_schema.h" + +static int +setup(void **state) +{ + const char *schema = + "module a {\n" + " namespace urn:tests:a;\n" + " prefix a;\n" + " yang-version 1.1;\n" + " 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;}\n" + " container c {\n" + " leaf x {type string;}\n" + " action act { input { leaf al {type string;} } output { leaf al {type uint8;} } }\n" + " notification n1 { leaf nl {type string;}}}\n" + " container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}\n" + " anydata any {config false;}\n" + " leaf foo2 { type string; default \"default-val\"; }\n" + " leaf foo3 { type uint32; }\n" + " 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_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE) + +#define PARSER_CHECK_ERROR(INPUT, PARSE_OPTION, VALIDATE_OPTION, MODEL, RET_VAL, ERR_MESSAGE, ERR_PATH) \ + assert_int_equal(RET_VAL, lyd_parse_data_mem(UTEST_LYCTX, INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, &MODEL));\ + CHECK_LOG_CTX(ERR_MESSAGE, ERR_PATH);\ + assert_null(MODEL) + +#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \ + CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, PRINT_OPTION) + +static void +test_leaf(void **state) +{ + const char *data = "foo value"; + struct lyd_node *tree; + struct lyd_node_term *leaf; + + assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL)); + + 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); + lyd_free_all(tree); + + /* make foo2 explicit */ + data = "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); + lyd_free_all(tree); + + /* parse foo2 but make it implicit, skip metadata xxx from missing schema */ + data = "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_true(leaf->flags & LYD_DEFAULT); + lyd_free_all(tree); + + /* invalid value */ + data = "val-aval-b10"; + PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "Invalid boolean value \"0\".", + "Data location \"/a:l1[a='val-a'][b='val-b'][c='1']/cont/e\", line number 1."); +} + +static void +test_anydata(void **state) +{ + const char *data; + struct lyd_node *tree; + + data = "\n" + " \n" + " a:data\n" + " \n" + " \n" + "\n"; + 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_R | LYS_STATUS_CURR | LYS_SET_CONFIG, 1, "any", + 1, LYS_ANYDATA, 0, 0, NULL, 0); + + const char *data_expected = + "\n" + " \n" + " a:data\n" + " \n" + " \n" + "\n"; + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected); + 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 = "oneone1"; + 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); + } + lyd_free_all(tree); + + /* missing keys */ + PARSER_CHECK_ERROR("1b", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "List instance is missing its key \"a\".", "Data location \"/a:l1[b='b'][c='1']\", line number 1."); + + PARSER_CHECK_ERROR("a", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "List instance is missing its key \"b\".", "Data location \"/a:l1[a='a']\", line number 1."); + + PARSER_CHECK_ERROR("ba", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "List instance is missing its key \"c\".", "Data location \"/a:l1[a='a'][b='b']\", line number 1."); + + /* key duplicate */ + PARSER_CHECK_ERROR("1ba1", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "Duplicate instance of \"c\".", + "Data location \"/a:l1[a='a'][b='b'][c='1'][c='1']/c\", line number 1."); + + /* keys order */ + CHECK_PARSE_LYD("da1b", 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("Invalid position of the key \"b\" in a list.", NULL); + lyd_free_all(tree); + + data = "1ba"; + 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; + 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("Invalid position of the key \"a\" in a list.", NULL); + lyd_free_all(tree); + + PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "Invalid position of the key \"b\" in a list.", "Data location \"/a:l1[c='1']/b\", line number 1."); +} + +static void +test_container(void **state) +{ + struct lyd_node *tree; + struct lyd_node_inner *cont; + + CHECK_PARSE_LYD("", 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); + lyd_free_all(tree); + + CHECK_PARSE_LYD("", 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); + lyd_free_all(tree); +} + +static void +test_opaq(void **state) +{ + const char *data; + struct lyd_node *tree; + + /* invalid value, no flags */ + data = ""; + PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "Invalid type uint32 empty value.", "Schema location \"/a:foo3\", line number 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_XML, "foo3", 0, 0, NULL, 0, ""); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "\n"); + lyd_free_all(tree); + + /* list, opaq flag */ + data = ""; + 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "\n"); + lyd_free_all(tree); + + /* missing key, no flags */ + data = "\n" + " val_a\n" + " val_b\n" + " val_d\n" + "\n"; + PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "List instance is missing its key \"c\".", + "Data location \"/a:l1[a='val_a'][b='val_b']\", line number 5."); + + /* 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + /* invalid key, no flags */ + data = "\n" + " val_a\n" + " val_b\n" + " val_c\n" + "\n"; + PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, + "Invalid type int16 value \"val_c\".", + "Data location \"/a:l1[a='val_a'][b='val_b']/c\", line number 4."); + + /* 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + /* opaq flag and fail */ + assert_int_equal(LY_EVALID, lyd_parse_data_mem(UTEST_LYCTX, + "\n" + " x\n" + " 1\n" + "\n", + LYD_XML, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree)); + CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Line number 3."); +} + +static void +test_rpc(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *op; + const struct lyd_node *node; + const char *dsc = "The operation loads all or part of a specified\n" + "configuration to the specified target configuration."; + const char *ref = "RFC 6241, Section 7.2"; + const char *feats[] = {"writable-running", NULL}; + + assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats))); + + data = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " val_a\n" + " val_b\n" + " val_c\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, 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-config", LYS_RPC, + 0, 0, 0, 0, 0, ref, 0); + + assert_non_null(tree); + + node = tree; + CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR, + 1, 0, 0, 1, "edit-config", LYS_RPC, + 0, 0, 0, 0, 0, ref, 0); + node = lyd_child(node)->next; + dsc = "Inline Config content."; + CHECK_LYSC_NODE(node->schema, dsc, 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config", 0, LYS_ANYXML, 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_XML, "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_XML, "l1", 0, 0, NULL, 0, ""); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " val_a\n" + " val_b\n" + " val_c\n" + " \n" + " \n" + "\n"); + + lyd_free_all(tree); + + /* wrong namespace, element name, whatever... */ + /* TODO */ +} + +static void +test_action(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *op; + + data = "\n" + " \n" + " value\n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, 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_WITHSIBLINGS, + "\n" + " \n" + " value\n" + " \n" + "\n"); + + 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 = "\n" + " \n" + " value\n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, 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_WITHSIBLINGS, data); + lyd_free_all(tree); + + /* top-level notif without envelope */ + data = "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, 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_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 = "\n" + " \n" + " 25\n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, 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_WITHSIBLINGS, "25\n"); + lyd_free_all(tree); + + /* wrong namespace, element name, whatever... */ + /* TODO */ +} + +static void +test_netconf_rpc(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *op; + const struct lyd_node *node; + const char *dsc = "The operation loads all or part of a specified\n" + "configuration to the specified target configuration."; + const char *ref = "RFC 6241, Section 7.2"; + const char *feats[] = {"writable-running", NULL}; + + assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats))); + + data = "" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " val_a\n" + " val_b\n" + " val_c\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_NETCONF, &tree, &op)); + ly_in_free(in, 0); + + assert_non_null(op); + + node = tree; + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 1, 0, LY_VALUE_XML, "rpc", 0, 0, 0, 0, ""); + + assert_non_null(tree); + + node = op; + CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR, + 1, 0, 0, 1, "edit-config", LYS_RPC, + 0, 0, 0, 0, 0, ref, 0); + node = lyd_child(node)->next; + dsc = "Inline Config content."; + CHECK_LYSC_NODE(node->schema, dsc, 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config", 0, LYS_ANYXML, 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_XML, "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_XML, "l1", 0, 0, NULL, 0, ""); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, + "\n"); + CHECK_LYD_STRING(op, LYD_PRINT_WITHSIBLINGS, + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " val_a\n" + " val_b\n" + " val_c\n" + " \n" + " \n" + "\n"); + + lyd_free_all(tree); + lyd_free_all(op); + + /* wrong namespace, element name, whatever... */ + /* TODO */ +} + +static void +test_netconf_action(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *op; + + data = "" + "" + "\n" + " \n" + " value\n" + " \n" + "\n" + "\n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_NETCONF, &tree, &op)); + ly_in_free(in, 0); + + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc", 0, 0, 0, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_VALUE_XML, "action", 0, 0, 0, 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_WITHSIBLINGS, + "\n" + " \n" + "\n"); + CHECK_LYD_STRING(op, LYD_PRINT_WITHSIBLINGS, + "\n" + " value\n" + "\n"); + + lyd_free_all(tree); + lyd_free_all(op); + + /* wrong namespace, element name, whatever... */ + /* TODO */ +} + +static void +test_netconf_reply_or_notification(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *action, *tree, *op, *op2; + + /* parse the action */ + data = "\n" + " \n" + " value\n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &action, &op)); + ly_in_free(in, 0); + + /* parse notification first */ + data = "\n" + "2010-12-06T08:00:01Z\n" + "\n" + " \n" + " value\n" + " \n" + "\n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_NOTIF_NETCONF, &tree, &op2)); + ly_in_free(in, 0); + + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 1, LY_VALUE_XML, "notification", 0, 0, 0, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_VALUE_XML, "eventTime", 0, 0, 0, 0, + "2010-12-06T08:00:01Z"); + + assert_non_null(op2); + CHECK_LYSC_NOTIF((struct lysc_node_notif *)op2->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, + "\n" + " 2010-12-06T08:00:01Z\n" + "\n"); + CHECK_LYD_STRING(op2, LYD_PRINT_WITHSIBLINGS, + "\n" + " value\n" + "\n"); + + lyd_free_all(tree); + lyd_free_all(op2); + + /* parse a data reply */ + data = "\n" + " 25\n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_REPLY_NETCONF, &tree, NULL)); + ly_in_free(in, 0); + + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 0, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, ""); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, + "\n"); + + lyd_free_all(tree); + /* it was connected to the action, do not free */ + + /* parse an ok reply */ + data = "\n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_REPLY_NETCONF, &tree, NULL)); + ly_in_free(in, 0); + + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_VALUE_XML, "ok", 0, 0, 0, 0, ""); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + + lyd_free_all(tree); + + /* parse an error reply */ + data = "\n" + " \n" + " rpc\n" + " missing-attribute\n" + " error\n" + " \n" + " message-id\n" + " rpc\n" + " \n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_REPLY_NETCONF, &tree, NULL)); + ly_in_free(in, 0); + + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 1, LY_VALUE_XML, "rpc-error", 0, 0, 0, 0, ""); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + + lyd_free_all(tree); + + lyd_free_all(action); + + /* wrong namespace, element name, whatever... */ + /* TODO */ +} + +static void +test_filter_attributes(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree; + const struct lyd_node *node; + const char *dsc; + const char *ref = "RFC 6241, Section 7.7"; + const char *feats[] = {"writable-running", NULL}; + + assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats))); + assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "notifications", "2008-07-14", NULL))); + + data = "\n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &tree, NULL)); + ly_in_free(in, 0); + assert_non_null(tree); + + node = tree; + dsc = "Retrieve running configuration and device state information."; + CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR, + 1, 0, 0, 1, "get", LYS_RPC, + 1, 0, 0, 0, 0, ref, 0); + node = lyd_child(node); + dsc = "This parameter specifies the portion of the system\nconfiguration and state data to retrieve."; + CHECK_LYSC_NODE(node->schema, dsc, 1, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "filter", 0, LYS_ANYXML, 1, 0, NULL, 0); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = "\n" + " \n" + " \n" + " \n" + "\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &tree, NULL)); + ly_in_free(in, 0); + assert_non_null(tree); + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); +} + +static void +test_data_skip(void **state) +{ + const char *data; + struct lyd_node *tree; + struct lyd_node_term *leaf; + + /* add invalid data to a module that is not implemented */ + data = ""; + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree)); + assert_null(tree); + + /* add invalid data to a module that is implemented */ + data = ""; + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree)); + assert_null(tree); + + /* first invalid, next valid */ + data = " 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"); + lyd_free_all(tree); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + UTEST(test_leaf, setup), + UTEST(test_anydata, 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_netconf_rpc, setup), + UTEST(test_netconf_action, setup), + UTEST(test_netconf_reply_or_notification, setup), + UTEST(test_filter_attributes, setup), + UTEST(test_data_skip, setup), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/utests/data/test_printer_xml.c b/tests/utests/data/test_printer_xml.c new file mode 100644 index 0000000..d533c41 --- /dev/null +++ b/tests/utests/data/test_printer_xml.c @@ -0,0 +1,343 @@ +/* + * @file test_printer_xml.c + * @author: Radek Krejci + * @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 + +#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 = ""; + CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); + /* canonized */ + data = ""; + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = ""; + 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 = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\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 = + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = "\n" + " \n" + " ahoj jak se vede < how are you" + " \n" + "\n"; + CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = "\n" + " ahoj \n" + " nazdar \n" + " ÄŒau \n" + "\n"; + CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = "\n" + " \n" + "\n"; + CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = "\n" + " \n" + " < how are you" + " \n" + "\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 = "aa"; + 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 = "/d:baa"; + CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + + data = "/d:b" + "aa"; + CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + + data = "/d:b" + "aa"; + 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 = "/d:baa"; + 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 = "/d:bvalaa"; + data_trim = "valaa"; + data_all = "/d:bvalaa"; + data_all_tag = "/d:b" + "val" + "aa"; + data_impl_tag = "/d:bvalaa"; + + 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 = "1020"; + reply = "30"; + result = "30"; + 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 = ""; + reply = ""; + result = ""; + 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 = "10test"; + reply = "test-reply"; + result = "10test-reply"; + 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); +} diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c new file mode 100644 index 0000000..27dba42 --- /dev/null +++ b/tests/utests/data/test_tree_data.c @@ -0,0 +1,597 @@ +/** + * @file test_tree_data.c + * @author: Radek Krejci + * @brief unit tests for functions from tress_data.c + * + * Copyright (c) 2018-2019 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 "common.h" +#include "libyang.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 = "abx"; + data2 = "aby"; + 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 = "ab"; + data2 = "b"; + 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)); + assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next->next, tree2->next, 0)); + lyd_free_all(tree1); + lyd_free_all(tree2); + + data1 = "ab"; + data2 = "b"; + 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 = "x"; + data2 = "y"; + 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 = "x"; + data2 = "xy"; + 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 = "x"; + data2 = "xy"; + 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 = "xy"; + 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); +} + +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 = "b"; + data2 = "b"; + 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 = "b"; + data2 = "b"; + 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 = "b"; + data2 = "b"; + 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 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 = "b"; + data2 = "b"; + 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 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 = "b"; + data2 = "b"; + 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 = "aa:x"; + data2 = "bb:x"; + 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 = "aa:x"; + data2 = "bb:y"; + 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 = "aa:x"; + data2 = "cc:x"; + 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 = "abx"; + 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 = "abx"; + result = "ab"; + 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 = "ab"; + result = "a"; + 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 = ""; + 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 = "a"; + 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 = "b"; + CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1); + assert_int_equal(LY_SUCCESS, lyd_dup_single(((struct lyd_node_inner *)((struct lyd_node_inner *)tree1->next)->child)->child, 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 = "abc"; + 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 = "b"; + 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(((struct lyd_node_inner *)((struct lyd_node_inner *)tree1->next)->child)->child, + (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 = "abcb"; + 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)); + 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 = + "" + " a" + " " + "" + " a" + " b" + " b" + " c" + "" + "" + ""; + + 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)); + term = lyd_target(path, tree); + + 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 = "test" + "oneone" + "twotwo" + "test"; + 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 = "one" + "two" + "three"; + 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 = "one" + "oneone" + "two" + "twotwo" + "three" + "threethree"; + 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 = "test" + "oneoneone" + "test"; + 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)); + 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 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 = + "" + " " + " " + " " + " " + ""; + + /* 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); + 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; +} + +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), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c new file mode 100644 index 0000000..415e16a --- /dev/null +++ b/tests/utests/data/test_validation.c @@ -0,0 +1,1460 @@ +/** + * @file test_validation.c + * @author: Radek Krejci + * @brief unit tests for functions from validation.c + * + * 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 +#include + +#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" + +#define LYD_TREE_CREATE(INPUT, MODEL) \ + CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL) + +static void +test_when(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module a {\n" + " namespace urn:tests:a;\n" + " prefix a;\n" + " yang-version 1.1;\n" + "\n" + " container cont {\n" + " leaf a {\n" + " when \"../../c = 'val_c'\";\n" + " type string;\n" + " }\n" + " leaf b {\n" + " type string;\n" + " }\n" + " }\n" + " leaf c {\n" + " when \"/cont/b = 'val_b'\";\n" + " type string;\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM("hey", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("When condition \"/cont/b = 'val_b'\" not satisfied.", "Data location \"/a:c\"."); + + LYD_TREE_CREATE("val_bhey", tree); + CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 0, LYS_LEAF, 0, 0, NULL, 1); + assert_int_equal(LYD_WHEN_TRUE, tree->next->flags); + lyd_free_all(tree); + + LYD_TREE_CREATE("valval_bval_c", tree); + CHECK_LYSC_NODE(lyd_child(tree)->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 1); + assert_int_equal(LYD_WHEN_TRUE, lyd_child(tree)->flags); + CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 0, LYS_LEAF, 0, 0, NULL, 1); + assert_int_equal(LYD_WHEN_TRUE, tree->next->flags); + lyd_free_all(tree); +} + +static void +test_mandatory_when(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module a {\n" + " namespace urn:tests:a;\n" + " prefix a;\n" + " yang-version 1.1;\n" + "\n" + " container cont {\n" + " leaf a {\n" + " type string;\n" + " }\n" + " leaf b {\n" + " when \"../a = 'val_a'\";\n" + " mandatory true;\n" + " type string;\n" + " }\n" + " }\n" + " leaf c {\n" + " type string;\n" + " }\n" + " leaf d {\n" + " when \"../c = 'val_c'\";\n" + " mandatory true;\n" + " type string;\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM("hey", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("When condition \"../c = 'val_c'\" not satisfied.", "Data location \"/a:d\"."); + + CHECK_PARSE_LYD_PARAM("hey", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("When condition \"../a = 'val_a'\" not satisfied.", "Data location \"/a:cont/b\"."); + + LYD_TREE_CREATE("val_chey", tree); + CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "d", 0, LYS_LEAF, 0, 0, NULL, 1); + assert_int_equal(LYD_WHEN_TRUE, tree->next->next->flags); + lyd_free_all(tree); + + LYD_TREE_CREATE("val_ahey", tree); + CHECK_LYSC_NODE(lyd_child(tree)->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "b", 0, LYS_LEAF, tree->schema, 0, NULL, 1); + assert_int_equal(LYD_WHEN_TRUE, lyd_child(tree)->next->flags); + lyd_free_all(tree); +} + +static void +test_type_incomplete_when(void **state) +{ + struct lys_module *mod; + struct lyd_node *tree; + const char *schema = + "module a {\n" + " namespace urn:tests:a;\n" + " prefix a;\n" + " yang-version 1.1;\n" + "\n" + " container cont {\n" + " when \"../c = 'val_c'\";\n" + " leaf a {\n" + " type leafref {\n" + " path \"/a:c\";\n" + " }\n" + " }\n" + " leaf b {\n" + " type string;\n" + " }\n" + " }\n" + " leaf c {\n" + " type string;\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod); + + LYD_TREE_CREATE("val_cvalval_c", tree); + + /* make the when false */ + assert_int_equal(LY_SUCCESS, lyd_change_term(tree->next, "wrong-val")); + + /* autodelete when with a leafref */ + assert_int_equal(LY_SUCCESS, lyd_validate_module(&tree, mod, 0, NULL)); + assert_string_equal(LYD_NAME(tree), "c"); + assert_null(tree->next); + + lyd_free_all(tree); +} + +static void +test_mandatory(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module b {\n" + " namespace urn:tests:b;\n" + " prefix b;\n" + " yang-version 1.1;\n" + "\n" + " choice choic {\n" + " mandatory true;\n" + " leaf a {\n" + " type string;\n" + " }\n" + " case b {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " leaf c {\n" + " mandatory true;\n" + " type string;\n" + " }\n" + " leaf d {\n" + " type empty;\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM("", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Mandatory choice \"choic\" data do not exist.", "Schema location \"/b:choic\".", "missing-choice"); + + CHECK_PARSE_LYD_PARAM("string", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Mandatory node \"c\" instance does not exist.", "Schema location \"/b:c\"."); + + CHECK_PARSE_LYD_PARAM("string", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Mandatory node \"c\" instance does not exist.", "Schema location \"/b:c\"."); + + LYD_TREE_CREATE("stringstring2", tree); + lyd_free_siblings(tree); +} + +static void +test_minmax(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module c {\n" + " namespace urn:tests:c;\n" + " prefix c;\n" + " yang-version 1.1;\n" + "\n" + " choice choic {\n" + " leaf a {\n" + " type string;\n" + " }\n" + " case b {\n" + " leaf-list l {\n" + " min-elements 3;\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " list lt {\n" + " max-elements 4;\n" + " key \"k\";\n" + " leaf k {\n" + " type string;\n" + " }\n" + " }\n" + " leaf d {\n" + " type empty;\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM("mate" + "", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "Schema location \"/c:choic/b/l\".", "too-few-elements"); + + CHECK_PARSE_LYD_PARAM("val1" + "val2", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "Schema location \"/c:choic/b/l\".", "too-few-elements"); + + LYD_TREE_CREATE("val1" + "val2" + "val3", tree); + lyd_free_all(tree); + + CHECK_PARSE_LYD_PARAM("val1" + "val2" + "val3" + "val1" + "val2" + "val3" + "val4" + "val5" + "val6", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Too many \"lt\" instances.", "Data location \"/c:lt[k='val5']\".", + "too-many-elements"); +} + +const char *schema_d = + "module d {\n" + " namespace urn:tests:d;\n" + " prefix d;\n" + " yang-version 1.1;\n" + "\n" + " list lt {\n" + " key \"k\";\n" + " unique \"l1\";\n" + " leaf k {\n" + " type string;\n" + " }\n" + " leaf l1 {\n" + " type string;\n" + " }\n" + " }\n" + " list lt2 {\n" + " key \"k\";\n" + " unique \"cont/l2 l4\";\n" + " unique \"l5 l6\";\n" + " leaf k {\n" + " type string;\n" + " }\n" + " container cont {\n" + " leaf l2 {\n" + " type string;\n" + " }\n" + " }\n" + " leaf l4 {\n" + " type string;\n" + " }\n" + " leaf l5 {\n" + " type string;\n" + " }\n" + " leaf l6 {\n" + " type string;\n" + " }\n" + " list lt3 {\n" + " key \"kk\";\n" + " unique \"l3\";\n" + " leaf kk {\n" + " type string;\n" + " }\n" + " leaf l3 {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + "}"; + +static void +test_unique(void **state) +{ + struct lyd_node *tree; + + UTEST_ADD_MODULE(schema_d, LYS_IN_YANG, NULL, NULL); + + LYD_TREE_CREATE("\n" + " val1\n" + " same\n" + "\n" + "\n" + " val2\n" + "", tree); + lyd_free_all(tree); + + LYD_TREE_CREATE("\n" + " val1\n" + " same\n" + "\n" + "\n" + " val2\n" + " not-same\n" + "", tree); + lyd_free_all(tree); + + CHECK_PARSE_LYD_PARAM("\n" + " val1\n" + " same\n" + "\n" + "\n" + " val2\n" + " same\n" + "", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l1\" not satisfied in \"/d:lt[k='val1']\" and \"/d:lt[k='val2']\".", + "Data location \"/d:lt[k='val2']\".", "data-not-unique"); + + /* now try with more instances */ + LYD_TREE_CREATE("\n" + " val1\n" + " 1\n" + "\n" + "\n" + " val2\n" + " 2\n" + "\n" + "\n" + " val3\n" + " 3\n" + "\n" + "\n" + " val4\n" + " 4\n" + "\n" + "\n" + " val5\n" + " 5\n" + "\n" + "\n" + " val6\n" + " 6\n" + "\n" + "\n" + " val7\n" + " 7\n" + "\n" + "\n" + " val8\n" + " 8\n" + "", tree); + lyd_free_all(tree); + + LYD_TREE_CREATE("\n" + " val1\n" + " 1\n" + "\n" + "\n" + " val2\n" + " 2\n" + "\n" + "\n" + " val3\n" + " 3\n" + "\n" + "\n" + " val4\n" + "\n" + "\n" + " val5\n" + " 5\n" + "\n" + "\n" + " val6\n" + " 6\n" + "\n" + "\n" + " val7\n" + "\n" + "\n" + " val8\n" + "", tree); + lyd_free_all(tree); + + CHECK_PARSE_LYD_PARAM("\n" + " val1\n" + " 1\n" + "\n" + "\n" + " val2\n" + " 2\n" + "\n" + "\n" + " val3\n" + "\n" + "\n" + " val4\n" + " 4\n" + "\n" + "\n" + " val5\n" + "\n" + "\n" + " val6\n" + "\n" + "\n" + " val7\n" + " 2\n" + "\n" + "\n" + " val8\n" + " 8\n" + "", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l1\" not satisfied in \"/d:lt[k='val7']\" and \"/d:lt[k='val2']\".", + "Data location \"/d:lt[k='val2']\".", "data-not-unique"); +} + +static void +test_unique_nested(void **state) +{ + struct lyd_node *tree; + + UTEST_ADD_MODULE(schema_d, LYS_IN_YANG, NULL, NULL); + + /* nested list uniquest are compared only with instances in the same parent list instance */ + LYD_TREE_CREATE("\n" + " val1\n" + " \n" + " 1\n" + " \n" + " 1\n" + "\n" + "\n" + " val2\n" + " \n" + " 2\n" + " \n" + " 2\n" + " \n" + " val1\n" + " 1\n" + " \n" + " \n" + " val2\n" + " 2\n" + " \n" + "\n" + "\n" + " val3\n" + " \n" + " 3\n" + " \n" + " 3\n" + " \n" + " val1\n" + " 2\n" + " \n" + "\n" + "\n" + " val4\n" + " \n" + " 4\n" + " \n" + " 4\n" + " \n" + " val1\n" + " 3\n" + " \n" + "\n" + "\n" + " val5\n" + " \n" + " 5\n" + " \n" + " 5\n" + " \n" + " val1\n" + " 3\n" + " \n" + "", tree); + lyd_free_all(tree); + + CHECK_PARSE_LYD_PARAM("\n" + " val1\n" + " \n" + " 1\n" + " \n" + " 1\n" + "\n" + "\n" + " val2\n" + " \n" + " 2\n" + " \n" + " \n" + " val1\n" + " 1\n" + " \n" + " \n" + " val2\n" + " 2\n" + " \n" + " \n" + " val3\n" + " 1\n" + " \n" + "\n" + "\n" + " val3\n" + " \n" + " 3\n" + " \n" + " 1\n" + " \n" + " val1\n" + " 2\n" + " \n" + "\n" + "\n" + " val4\n" + " \n" + " 4\n" + " \n" + " \n" + " val1\n" + " 3\n" + " \n" + "\n" + "\n" + " val5\n" + " \n" + " 5\n" + " \n" + " \n" + " val1\n" + " 3\n" + " \n" + "", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l3\" not satisfied in \"/d:lt2[k='val2']/lt3[kk='val3']\" and " + "\"/d:lt2[k='val2']/lt3[kk='val1']\".", + "Data location \"/d:lt2[k='val2']/lt3[kk='val1']\".", "data-not-unique"); + + CHECK_PARSE_LYD_PARAM("\n" + " val1\n" + " \n" + " 1\n" + " \n" + " 1\n" + "\n" + "\n" + " val2\n" + " \n" + " 2\n" + " \n" + " 2\n" + "\n" + "\n" + " val3\n" + " \n" + " 3\n" + " \n" + " 3\n" + "\n" + "\n" + " val4\n" + " \n" + " 2\n" + " \n" + " 2\n" + "\n" + "\n" + " val5\n" + " \n" + " 5\n" + " \n" + " 5\n" + "", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"cont/l2 l4\" not satisfied in \"/d:lt2[k='val4']\" and \"/d:lt2[k='val2']\".", + "Data location \"/d:lt2[k='val2']\".", "data-not-unique"); + + CHECK_PARSE_LYD_PARAM("\n" + " val1\n" + " \n" + " 1\n" + " \n" + " 1\n" + " 1\n" + " 1\n" + "\n" + "\n" + " val2\n" + " \n" + " 2\n" + " \n" + " 1\n" + " 1\n" + "\n" + "\n" + " val3\n" + " \n" + " 3\n" + " \n" + " 1\n" + " 3\n" + " 3\n" + "\n" + "\n" + " val4\n" + " \n" + " 4\n" + " \n" + " 1\n" + " 1\n" + "\n" + "\n" + " val5\n" + " \n" + " 5\n" + " \n" + " 1\n" + " 3\n" + " 3\n" + "", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l5 l6\" not satisfied in \"/d:lt2[k='val5']\" and \"/d:lt2[k='val3']\".", + "Data location \"/d:lt2[k='val3']\".", "data-not-unique"); +} + +static void +test_dup(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module e {\n" + " namespace urn:tests:e;\n" + " prefix e;\n" + " yang-version 1.1;\n" + "\n" + " choice choic {\n" + " leaf a {\n" + " type string;\n" + " }\n" + " case b {\n" + " leaf-list l {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " list lt {\n" + " key \"k\";\n" + " leaf k {\n" + " type string;\n" + " }\n" + " }\n" + " leaf d {\n" + " type uint32;\n" + " }\n" + " leaf-list ll {\n" + " type string;\n" + " }\n" + " container cont {\n" + " list lt {\n" + " key \"k\";\n" + " leaf k {\n" + " type string;\n" + " }\n" + " }\n" + " leaf d {\n" + " type uint32;\n" + " }\n" + " leaf-list ll {\n" + " type string;\n" + " }\n" + " leaf-list ll2 {\n" + " type enumeration {\n" + " enum one;\n" + " enum two;\n" + " }\n" + " }\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM("2550", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"d\".", "Data location \"/e:d\"."); + + CHECK_PARSE_LYD_PARAM("A" + "B" + "A", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"lt\".", "Data location \"/e:lt[k='A']\"."); + + CHECK_PARSE_LYD_PARAM("A" + "B" + "B", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"ll\".", "Data location \"/e:ll[.='B']\"."); + + CHECK_PARSE_LYD_PARAM("", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"cont\".", "Data location \"/e:cont\"."); + + /* same tests again but using hashes */ + CHECK_PARSE_LYD_PARAM("25501234", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"d\".", "Data location \"/e:cont/d\", line number 1."); + + CHECK_PARSE_LYD_PARAM("1234" + "a" + "b" + "c" + "d" + "c", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"lt\".", "Data location \"/e:cont/lt[k='c']\", line number 1."); + + CHECK_PARSE_LYD_PARAM("1234" + "abcdd", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"ll\".", "Data location \"/e:cont/ll[.='d']\", line number 1."); + + /* cases */ + CHECK_PARSE_LYD_PARAM("a" + "b" + "c" + "b", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Duplicate instance of \"l\".", "Data location \"/e:l[.='b']\"."); + + CHECK_PARSE_LYD_PARAM("ab" + "c" + "aa", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Data for both cases \"a\" and \"b\" exist.", "Schema location \"/e:choic\"."); +} + +static void +test_defaults(void **state) +{ + struct lyd_node *tree, *node, *diff; + struct lys_module *mod; + const char *schema = + "module f {\n" + " namespace urn:tests:f;\n" + " prefix f;\n" + " yang-version 1.1;\n" + "\n" + " choice choic {\n" + " default \"c\";\n" + " leaf a {\n" + " type string;\n" + " }\n" + " case b {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " }\n" + " case c {\n" + " leaf-list ll1 {\n" + " type string;\n" + " default \"def1\";\n" + " default \"def2\";\n" + " default \"def3\";\n" + " }\n" + " }\n" + " }\n" + " leaf d {\n" + " type uint32;\n" + " default 15;\n" + " }\n" + " leaf dd {\n" + " type uint32;\n" + " when '../d = 666';\n" + " default 15;\n" + " }\n" + " leaf-list ll2 {\n" + " type string;\n" + " default \"dflt1\";\n" + " default \"dflt2\";\n" + " }\n" + " container cont {\n" + " choice choic {\n" + " default \"c\";\n" + " leaf a {\n" + " type string;\n" + " }\n" + " case b {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " }\n" + " case c {\n" + " leaf-list ll1 {\n" + " type string;\n" + " default \"def1\";\n" + " default \"def2\";\n" + " default \"def3\";\n" + " }\n" + " }\n" + " }\n" + " leaf d {\n" + " type uint32;\n" + " default 15;\n" + " }\n" + " leaf dd {\n" + " type uint32;\n" + " when '../d = 666';\n" + " default 15;\n" + " }\n" + " leaf-list ll2 {\n" + " type string;\n" + " default \"dflt1\";\n" + " default \"dflt2\";\n" + " }\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod); + + 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));\ + + /* get defaults */ + tree = NULL; + assert_int_equal(lyd_validate_module(&tree, mod, 0, &diff), LY_SUCCESS); + assert_non_null(tree); + assert_non_null(diff); + + /* check all defaults exist */ + CHECK_LYD_STRING_PARAM(tree, + "def1\n" + "def2\n" + "def3\n" + "15\n" + "dflt1\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS); + + /* check diff */ + CHECK_LYD_STRING_PARAM(diff, + "def1\n" + "def2\n" + "def3\n" + "15\n" + "dflt1\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS); + lyd_free_all(diff); + + /* create another explicit case and validate */ + assert_int_equal(lyd_new_term(NULL, mod, "l", "value", 0, &node), LY_SUCCESS); + assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS); + assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS); + + /* check data tree */ + CHECK_LYD_STRING_PARAM(tree, + "value\n" + "15\n" + "dflt1\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS); + + /* check diff */ + CHECK_LYD_STRING_PARAM(diff, + "def1\n" + "def2\n" + "def3\n", + LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS); + lyd_free_all(diff); + + /* create explicit leaf-list and leaf and validate */ + assert_int_equal(lyd_new_term(NULL, mod, "d", "15", 0, &node), LY_SUCCESS); + assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS); + assert_int_equal(lyd_new_term(NULL, mod, "ll2", "dflt2", 0, &node), LY_SUCCESS); + assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS); + assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS); + + /* check data tree */ + CHECK_LYD_STRING_PARAM(tree, + "value\n" + "15\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS); + + /* check diff */ + CHECK_LYD_STRING_PARAM(diff, + "15\n" + "dflt1\n" + "dflt2\n", + LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS); + lyd_free_all(diff); + + /* create first explicit container, which should become implicit */ + assert_int_equal(lyd_new_inner(NULL, mod, "cont", 0, &node), LY_SUCCESS); + assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS); + assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS); + + /* check data tree */ + CHECK_LYD_STRING_PARAM(tree, + "value\n" + "15\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS); + /* check diff */ + assert_null(diff); + + /* create second explicit container, which should become implicit, so the first tree node should be removed */ + assert_int_equal(lyd_new_inner(NULL, mod, "cont", 0, &node), LY_SUCCESS); + assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS); + assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS); + + /* check data tree */ + CHECK_LYD_STRING_PARAM(tree, + "value\n" + "15\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS); + /* check diff */ + assert_null(diff); + + /* similar changes for nested defaults */ + assert_int_equal(lyd_new_term(tree->prev, NULL, "ll1", "def3", 0, NULL), LY_SUCCESS); + assert_int_equal(lyd_new_term(tree->prev, NULL, "d", "5", 0, NULL), LY_SUCCESS); + assert_int_equal(lyd_new_term(tree->prev, NULL, "ll2", "non-dflt", 0, NULL), LY_SUCCESS); + assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS); + + /* check data tree */ + CHECK_LYD_STRING_PARAM(tree, + "value\n" + "15\n" + "dflt2\n" + "\n" + " def3\n" + " 5\n" + " non-dflt\n" + "\n", + LYD_XML, LYD_PRINT_WITHSIBLINGS); + + /* check diff */ + CHECK_LYD_STRING_PARAM(diff, + "\n" + " def1\n" + " def2\n" + " def3\n" + " 15\n" + " dflt1\n" + " dflt2\n" + "\n", + LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS); + lyd_free_all(diff); + lyd_free_all(tree); + + /* check data tree - when enabled node */ + CHECK_PARSE_LYD_PARAM("666666", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); + CHECK_LYD_STRING_PARAM(tree, + "def1\n" + "def2\n" + "def3\n" + "666\n" + "
15
\n" + "dflt1\n" + "dflt2\n" + "\n" + " def1\n" + " def2\n" + " def3\n" + " 666\n" + "
15
\n" + " dflt1\n" + " dflt2\n" + "
\n", + LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS); + lyd_free_all(tree); +} + +static void +test_state(void **state) +{ + const char *data; + struct lyd_node *tree; + const char *schema = + "module h {\n" + " namespace urn:tests:h;\n" + " prefix h;\n" + " yang-version 1.1;\n" + "\n" + " container cont {\n" + " container cont2 {\n" + " config false;\n" + " leaf l {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + data = "\n" + " \n" + " val\n" + " \n" + "\n"; + CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_NO_STATE, 0, LY_EVALID, tree); + CHECK_LOG_CTX("Unexpected data state node \"cont2\" found.", + "Data location \"/h:cont/cont2\", line number 3."); + + CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT | LYD_VALIDATE_NO_STATE, NULL)); + CHECK_LOG_CTX("Unexpected data state node \"cont2\" found.", + "Data location \"/h:cont/cont2\"."); + lyd_free_all(tree); +} + +static void +test_must(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module i {\n" + " namespace urn:tests:i;\n" + " prefix i;\n" + " yang-version 1.1;\n" + "\n" + " container cont {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " leaf l2 {\n" + " must \"../l = 'right'\";\n" + " type string;\n" + " }\n" + " leaf l3 {\n" + " must \"../l = 'left'\" {\n" + " error-app-tag \"not-left\";\n" + " error-message \"l leaf is not left\";\n" + " }\n" + " type string;\n" + " }\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM("\n" + " wrong\n" + " val\n" + "\n", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", + "Data location \"/i:cont/l2\".", "must-violation"); + + LYD_TREE_CREATE("\n" + " right\n" + " val\n" + "\n", tree); + lyd_free_all(tree); + + CHECK_PARSE_LYD_PARAM("\n" + " wrong\n" + " val\n" + "\n", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/i:cont/l3\".", "not-left"); +} + +const char *schema_j = + "module j {\n" + " namespace urn:tests:j;\n" + " prefix j;\n" + " yang-version 1.1;\n" + "\n" + " feature feat1;\n" + "\n" + " container cont {\n" + " must \"false()\";\n" + " list l1 {\n" + " key \"k\";\n" + " leaf k {\n" + " type string;\n" + " }\n" + " action act {\n" + " if-feature feat1;\n" + " input {\n" + " must \"../../lf1 = 'true'\";\n" + " leaf lf2 {\n" + " type leafref {\n" + " path /lf3;\n" + " }\n" + " }\n" + " }\n" + " output {\n" + " must \"../../lf1 = 'true2'\";\n" + " leaf lf2 {\n" + " type leafref {\n" + " path /lf4;\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + "\n" + " leaf lf1 {\n" + " type string;\n" + " }\n" + " }\n" + "\n" + " leaf lf3 {\n" + " type string;\n" + " }\n" + "\n" + " leaf lf4 {\n" + " type string;\n" + " }\n" + "}"; +const char *feats_j[] = {"feat1", NULL}; + +static void +test_action(void **state) +{ + struct ly_in *in; + struct lyd_node *tree, *op_tree; + + UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory( + "\n" + " \n" + " val1\n" + " \n" + " target\n" + " \n" + " \n" + "\n", &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &op_tree, NULL)); + assert_non_null(op_tree); + + /* missing leafref */ + assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, NULL, LYD_TYPE_RPC_YANG, NULL)); + CHECK_LOG_CTX("Invalid leafref value \"target\" - no target instance \"/lf3\" with the same value.", + "Data location \"/j:cont/l1[k='val1']/act/lf2\"."); + ly_in_free(in, 0); + + CHECK_PARSE_LYD_PARAM("\n" + " not true\n" + "\n" + "target\n", + LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + + /* input must false */ + assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, tree, LYD_TYPE_RPC_YANG, NULL)); + CHECK_LOG_CTX("Must condition \"../../lf1 = 'true'\" not satisfied.", + "Data location \"/j:cont/l1[k='val1']/act\"."); + + lyd_free_all(tree); + CHECK_PARSE_LYD_PARAM("\n" + " true\n" + "\n" + "target\n", + LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + + /* success */ + assert_int_equal(LY_SUCCESS, lyd_validate_op(op_tree, tree, LYD_TYPE_RPC_YANG, NULL)); + + lyd_free_tree(op_tree); + lyd_free_siblings(tree); +} + +static void +test_rpc(void **state) +{ + const char *schema, *data; + struct ly_in *in; + struct lyd_node *tree; + + /* Testing constraint violation in RPC. */ + schema = + "module val-str {\n" + " namespace \"urn:vstr\";\n" + " prefix v;\n" + "\n" + " rpc modify-user-password {\n" + " input {\n" + " leaf old-password {\n" + " type string {\n" + " length \"4..8\";\n" + " }\n" + " }\n" + " leaf new-password {\n" + " type string {\n" + " length \"4..8\";\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}\n"; + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + data = + "\n" + " 12345\n" + " 123\n" + ""; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &tree, NULL)); + CHECK_LOG_CTX("Unsatisfied length - string \"123\" length is not allowed.", + "Data location \"/val-str:modify-user-password/new-password\", line number 3."); + ly_in_free(in, 0); +} + +static void +test_reply(void **state) +{ + struct ly_in *in; + struct lyd_node *tree, *op_tree; + + UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory( + "\n" + " \n" + " val1\n" + " \n" + " target\n" + " \n" + " \n" + "\n", &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_REPLY_YANG, &op_tree, NULL)); + assert_non_null(op_tree); + ly_in_free(in, 0); + + /* missing leafref */ + assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, NULL, LYD_TYPE_REPLY_YANG, NULL)); + CHECK_LOG_CTX("Invalid leafref value \"target\" - no target instance \"/lf4\" with the same value.", + "Data location \"/j:cont/l1[k='val1']/act/lf2\"."); + + CHECK_PARSE_LYD_PARAM("\n" + " not true\n" + "\n" + "target\n", + LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + + /* input must false */ + assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, tree, LYD_TYPE_REPLY_YANG, NULL)); + CHECK_LOG_CTX("Must condition \"../../lf1 = 'true2'\" not satisfied.", "Data location \"/j:cont/l1[k='val1']/act\"."); + + lyd_free_all(tree); + CHECK_PARSE_LYD_PARAM("\n" + " true2\n" + "\n" + "target\n", + LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + + /* success */ + assert_int_equal(LY_SUCCESS, lyd_validate_op(op_tree, tree, LYD_TYPE_REPLY_YANG, NULL)); + + lyd_free_tree(op_tree); + lyd_free_all(tree); +} + +static void +test_case(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module k {\n" + " namespace urn:tests:k;\n" + " prefix k;\n" + " yang-version 1.1;\n" + "\n" + " container ch {\n" + " choice a0 {\n" + " case v0 {\n" + " leaf g0 {\n" + " type string;\n" + " }\n" + " }\n" + " case v1 {\n" + " choice a1 {\n" + " case r0 {\n" + " leaf g1 {\n" + " type string;\n" + " }\n" + " }\n" + " case r1 {\n" + " leaf g2 {\n" + " type string;\n" + " }\n" + " leaf g3 {\n" + " type string;\n" + " }\n" + " }\n" + " case r2 {\n" + " leaf g4 {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " }\n" + " case v2 {\n" + " choice a2 {\n" + " case y0 {\n" + " leaf g5 {\n" + " type string;\n" + " }\n" + " }\n" + " case y1 {\n" + " leaf g6 {\n" + " type string;\n" + " }\n" + " leaf g7 {\n" + " type string;\n" + " }\n" + " }\n" + " case y2 {\n" + " leaf g8 {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + CHECK_PARSE_LYD_PARAM( + "{\n" + " \"k:ch\": {\n" + " \"g0\": \"value_g0\",\n" + " \"g7\": \"value_g7\"\n" + " }\n" + "}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.", + "Data location \"/k:ch\", line number 5."); + + CHECK_PARSE_LYD_PARAM( + "{\n" + " \"k:ch\": {\n" + " \"g7\": \"value_g7\",\n" + " \"g0\": \"value_g0\"\n" + " }\n" + "}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.", + "Data location \"/k:ch\", line number 5."); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + UTEST(test_when), + UTEST(test_mandatory), + UTEST(test_mandatory_when), + UTEST(test_type_incomplete_when), + UTEST(test_minmax), + UTEST(test_unique), + UTEST(test_unique_nested), + UTEST(test_dup), + UTEST(test_defaults), + UTEST(test_state), + UTEST(test_must), + UTEST(test_action), + UTEST(test_rpc), + UTEST(test_reply), + UTEST(test_case), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} -- cgit v1.2.3