| /** |
| * @file test_merge.c |
| * @author Michal Vasko <mvasko@cesnet.cz> |
| * @brief tests for complex data merges. |
| * |
| * Copyright (c) 2020 CESNET, z.s.p.o. |
| * |
| * This source code is licensed under BSD 3-Clause License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * https://opensource.org/licenses/BSD-3-Clause |
| */ |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| |
| #include "libyang.h" |
| |
| struct state { |
| struct ly_ctx *ctx; |
| struct lyd_node *source; |
| struct lyd_node *target; |
| struct lyd_node *result; |
| }; |
| |
| static int |
| setup_dflt(void **state) |
| { |
| struct state *st; |
| |
| (*state) = st = calloc(1, sizeof *st); |
| if (!st) { |
| fprintf(stderr, "Memory allocation error.\n"); |
| return -1; |
| } |
| |
| /* libyang context */ |
| if (ly_ctx_new(NULL, 0, &st->ctx)) { |
| fprintf(stderr, "Failed to create context.\n"); |
| goto error; |
| } |
| |
| return 0; |
| |
| error: |
| ly_ctx_destroy(st->ctx, NULL); |
| free(st); |
| (*state) = NULL; |
| |
| return -1; |
| } |
| |
| static int |
| teardown_dflt(void **state) |
| { |
| struct state *st = (*state); |
| |
| lyd_free_siblings(st->target); |
| lyd_free_siblings(st->source); |
| lyd_free_siblings(st->result); |
| ly_ctx_destroy(st->ctx, NULL); |
| free(st); |
| (*state) = NULL; |
| |
| return 0; |
| } |
| |
| static void |
| test_batch(void **state) |
| { |
| struct state *st = (*state); |
| uint32_t i; |
| char *str; |
| |
| const char *start = |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>yang</name>" |
| "<revision>2016-02-11</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>"; |
| const char *data[] = { |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-yang-library</name>" |
| "<revision>2016-02-01</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf-acm</name>" |
| "<revision>2012-02-22</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf</name>" |
| "<revision>2011-06-01</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf-monitoring</name>" |
| "<revision>2010-10-04</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf-with-defaults</name>" |
| "<revision>2011-06-01</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>yang</name>" |
| "<revision>2016-02-11</revision>" |
| "<namespace>urn:ietf:params:xml:ns:yang:1</namespace>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-yang-library</name>" |
| "<revision>2016-02-01</revision>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf-acm</name>" |
| "<revision>2012-02-22</revision>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf</name>" |
| "<revision>2011-06-01</revision>" |
| "<namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>" |
| "<feature>writable-running</feature>" |
| "<feature>candidate</feature>" |
| "<feature>rollback-on-error</feature>" |
| "<feature>validate</feature>" |
| "<feature>startup</feature>" |
| "<feature>xpath</feature>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf-monitoring</name>" |
| "<revision>2010-10-04</revision>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| , |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>ietf-netconf-with-defaults</name>" |
| "<revision>2011-06-01</revision>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>" |
| "<conformance-type>implement</conformance-type>" |
| "</module>" |
| "</modules-state>" |
| }; |
| const char *output_template = |
| "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" |
| "<module>" |
| "<name>yang</name>" |
| "<revision>2016-02-11</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "<namespace>urn:ietf:params:xml:ns:yang:1</namespace>" |
| "</module>" |
| "<module>" |
| "<name>ietf-yang-library</name>" |
| "<revision>2016-02-01</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>" |
| "</module>" |
| "<module>" |
| "<name>ietf-netconf-acm</name>" |
| "<revision>2012-02-22</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>" |
| "</module>" |
| "<module>" |
| "<name>ietf-netconf</name>" |
| "<revision>2011-06-01</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "<namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>" |
| "<feature>writable-running</feature>" |
| "<feature>candidate</feature>" |
| "<feature>rollback-on-error</feature>" |
| "<feature>validate</feature>" |
| "<feature>startup</feature>" |
| "<feature>xpath</feature>" |
| "</module>" |
| "<module>" |
| "<name>ietf-netconf-monitoring</name>" |
| "<revision>2010-10-04</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>" |
| "</module>" |
| "<module>" |
| "<name>ietf-netconf-with-defaults</name>" |
| "<revision>2011-06-01</revision>" |
| "<conformance-type>implement</conformance-type>" |
| "<namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>" |
| "</module>" |
| "</modules-state>"; |
| struct ly_in *in = NULL; |
| |
| assert_int_equal(LY_SUCCESS, ly_in_new_memory(start, &in)); |
| assert_int_equal(LY_SUCCESS, lyd_parse_data(st->ctx, in, LYD_XML, LYD_PARSE_ONLY, 0, &st->target)); |
| assert_non_null(st->target); |
| |
| for (i = 0; i < 11; ++i) { |
| ly_in_memory(in, data[i]); |
| assert_int_equal(LY_SUCCESS, lyd_parse_data(st->ctx, in, LYD_XML, LYD_PARSE_ONLY, 0, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_merge(&st->target, st->source, LYD_MERGE_DESTRUCT)); |
| st->source = NULL; |
| } |
| |
| lyd_print_mem(&str, st->target, LYD_XML, 0); |
| assert_string_equal(str, output_template); |
| |
| ly_in_free(in, 0); |
| free(str); |
| } |
| |
| static void |
| test_leaf(void **state) |
| { |
| struct state *st = (*state); |
| const char *sch = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " container A {" |
| " leaf f1 {type string;}" |
| " container B {" |
| " leaf f2 {type string;}" |
| " }" |
| " }" |
| " }"; |
| const char *trg = "<A xmlns=\"urn:x\"> <f1>block</f1> </A>"; |
| const char *src = "<A xmlns=\"urn:x\"> <f1>aa</f1> <B> <f2>bb</f2> </B> </A>"; |
| const char *result = "<A xmlns=\"urn:x\"><f1>aa</f1><B><f2>bb</f2></B></A>"; |
| char *printed = NULL; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, src, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, trg, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->target)); |
| assert_non_null(st->target); |
| |
| /* merge them */ |
| assert_int_equal(lyd_merge(&st->target, st->source, 0), LY_SUCCESS); |
| assert_int_equal(lyd_validate(&st->target, NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| /* check the result */ |
| lyd_print_mem(&printed, st->target, LYD_XML, LYD_PRINT_WITHSIBLINGS); |
| assert_string_equal(printed, result); |
| free(printed); |
| } |
| |
| static void |
| test_container(void **state) |
| { |
| struct state *st = (*state); |
| const char *sch = |
| "module A {" |
| "namespace \"aa:A\";" |
| "prefix A;" |
| "container A {" |
| "leaf f1 {type string;}" |
| "container B {" |
| "leaf f2 {type string;}" |
| "}" |
| "container C {" |
| "leaf f3 {type string;}" |
| "}" |
| "}" |
| "}"; |
| |
| const char *trg = "<A xmlns=\"aa:A\"> <B> <f2>aaa</f2> </B> </A>"; |
| const char *src = "<A xmlns=\"aa:A\"> <C> <f3>bbb</f3> </C> </A>"; |
| const char *result = "<A xmlns=\"aa:A\"><B><f2>aaa</f2></B><C><f3>bbb</f3></C></A>"; |
| char *printed = NULL; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, src, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, trg, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->target)); |
| assert_non_null(st->target); |
| |
| /* merge them */ |
| assert_int_equal(lyd_merge(&st->target, st->source, 0), LY_SUCCESS); |
| assert_int_equal(lyd_validate(&st->target, NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| /* check the result */ |
| lyd_print_mem(&printed, st->target, LYD_XML, LYD_PRINT_WITHSIBLINGS); |
| assert_string_equal(printed, result); |
| free(printed); |
| } |
| |
| static void |
| test_list(void **state) |
| { |
| struct state *st = (*state); |
| const char *sch = |
| "module merge {" |
| "namespace \"http://test/merge\";" |
| "prefix merge;" |
| |
| "container inner1 {" |
| "list b-list1 {" |
| "key p1;" |
| "leaf p1 {" |
| "type uint8;" |
| "}" |
| "leaf p2 {" |
| "type string;" |
| "}" |
| "leaf p3 {" |
| "type boolean;" |
| "default false;" |
| "}" |
| "}" |
| "}" |
| "}"; |
| |
| |
| const char *trg = |
| "<inner1 xmlns=\"http://test/merge\">" |
| "<b-list1>" |
| "<p1>1</p1>" |
| "<p2>a</p2>" |
| "<p3>true</p3>" |
| "</b-list1>" |
| "</inner1>"; |
| const char *src = |
| "<inner1 xmlns=\"http://test/merge\">" |
| "<b-list1>" |
| "<p1>1</p1>" |
| "<p2>b</p2>" |
| "</b-list1>" |
| "</inner1>"; |
| const char *result = |
| "<inner1 xmlns=\"http://test/merge\">" |
| "<b-list1>" |
| "<p1>1</p1>" |
| "<p2>b</p2>" |
| "<p3>true</p3>" |
| "</b-list1>" |
| "</inner1>"; |
| char *printed = NULL; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, src, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, trg, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->target)); |
| assert_non_null(st->target); |
| |
| /* merge them */ |
| assert_int_equal(lyd_merge(&st->target, st->source, LYD_MERGE_EXPLICIT), LY_SUCCESS); |
| assert_int_equal(lyd_validate(&st->target, NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| /* check the result */ |
| lyd_print_mem(&printed, st->target, LYD_XML, LYD_PRINT_WITHSIBLINGS); |
| assert_string_equal(printed, result); |
| free(printed); |
| } |
| |
| static void |
| test_list2(void **state) |
| { |
| struct state *st = (*state); |
| const char *sch = |
| "module merge {" |
| "namespace \"http://test/merge\";" |
| "prefix merge;" |
| |
| "container inner1 {" |
| "list b-list1 {" |
| "key p1;" |
| "leaf p1 {" |
| "type uint8;" |
| "}" |
| "leaf p2 {" |
| "type string;" |
| "}" |
| "container inner2 {" |
| "leaf p3 {" |
| "type boolean;" |
| "default false;" |
| "}" |
| "leaf p4 {" |
| "type string;" |
| "}" |
| "}" |
| "}" |
| "}" |
| "}"; |
| |
| |
| const char *trg = |
| "<inner1 xmlns=\"http://test/merge\">" |
| "<b-list1>" |
| "<p1>1</p1>" |
| "<p2>a</p2>" |
| "<inner2>" |
| "<p4>val</p4>" |
| "</inner2>" |
| "</b-list1>" |
| "</inner1>"; |
| const char *src = |
| "<inner1 xmlns=\"http://test/merge\">" |
| "<b-list1>" |
| "<p1>1</p1>" |
| "<p2>b</p2>" |
| "</b-list1>" |
| "</inner1>"; |
| const char *result = |
| "<inner1 xmlns=\"http://test/merge\">" |
| "<b-list1>" |
| "<p1>1</p1>" |
| "<p2>b</p2>" |
| "<inner2>" |
| "<p4>val</p4>" |
| "</inner2>" |
| "</b-list1>" |
| "</inner1>"; |
| char *printed = NULL; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, src, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, trg, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->target)); |
| assert_non_null(st->target); |
| |
| /* merge them */ |
| assert_int_equal(lyd_merge(&st->target, st->source, LYD_MERGE_EXPLICIT), LY_SUCCESS); |
| assert_int_equal(lyd_validate(&st->target, NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| /* check the result */ |
| lyd_print_mem(&printed, st->target, LYD_XML, LYD_PRINT_WITHSIBLINGS); |
| assert_string_equal(printed, result); |
| free(printed); |
| } |
| |
| static void |
| test_case(void **state) |
| { |
| struct state *st = (*state); |
| const char *sch = |
| "module merge {" |
| "namespace \"http://test/merge\";" |
| "prefix merge;" |
| "container cont {" |
| "choice ch {" |
| "container inner {" |
| "leaf p1 {" |
| "type string;" |
| "}" |
| "}" |
| "case c2 {" |
| "leaf p1 {" |
| "type string;" |
| "}" |
| "}" |
| "}" |
| "}" |
| "}"; |
| |
| const char *trg = |
| "<cont xmlns=\"http://test/merge\">" |
| "<inner>" |
| "<p1>1</p1>" |
| "</inner>" |
| "</cont>"; |
| const char *src = |
| "<cont xmlns=\"http://test/merge\">" |
| "<p1>1</p1>" |
| "</cont>"; |
| const char *result = |
| "<cont xmlns=\"http://test/merge\">" |
| "<p1>1</p1>" |
| "</cont>"; |
| char *printed = NULL; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, src, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, trg, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->target)); |
| assert_non_null(st->target); |
| |
| /* merge them */ |
| assert_int_equal(lyd_merge(&st->target, st->source, 0), LY_SUCCESS); |
| assert_int_equal(lyd_validate(&st->target, NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| /* check the result */ |
| lyd_print_mem(&printed, st->target, LYD_XML, LYD_PRINT_WITHSIBLINGS); |
| assert_string_equal(printed, result); |
| free(printed); |
| } |
| |
| static void |
| test_dflt(void **state) |
| { |
| struct state *st = (*state); |
| struct lyd_node *tmp; |
| const char *sch = |
| "module merge-dflt {" |
| "namespace \"urn:merge-dflt\";" |
| "prefix md;" |
| "container top {" |
| "leaf a {" |
| "type string;" |
| "}" |
| "leaf b {" |
| "type string;" |
| "}" |
| "leaf c {" |
| "type string;" |
| "default \"c_dflt\";" |
| "}" |
| "}" |
| "}"; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| st->target = lyd_new_path(NULL, st->ctx, "/merge-dflt:top/c", "c_dflt", 0); |
| assert_non_null(st->target); |
| assert_int_equal(lyd_validate(&(st->target), NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| st->source = lyd_new_path(NULL, st->ctx, "/merge-dflt:top/a", "a_val", 0); |
| assert_non_null(st->source); |
| tmp = lyd_new_path(st->source, st->ctx, "/merge-dflt:top/b", "b_val", 0); |
| assert_non_null(tmp); |
| assert_int_equal(lyd_validate(&(st->source), NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| assert_int_equal(lyd_merge(&st->target, st->source, LYD_MERGE_DESTRUCT), LY_SUCCESS); |
| st->source = NULL; |
| |
| /* c should be replaced and now be default */ |
| assert_true(lyd_node_children(st->target, 0)->flags & LYD_DEFAULT); |
| } |
| |
| static void |
| test_dflt2(void **state) |
| { |
| struct state *st = (*state); |
| struct lyd_node *tmp; |
| const char *sch = |
| "module merge-dflt {" |
| "namespace \"urn:merge-dflt\";" |
| "prefix md;" |
| "container top {" |
| "leaf a {" |
| "type string;" |
| "}" |
| "leaf b {" |
| "type string;" |
| "}" |
| "leaf c {" |
| "type string;" |
| "default \"c_dflt\";" |
| "}" |
| "}" |
| "}"; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| st->target = lyd_new_path(NULL, st->ctx, "/merge-dflt:top/c", "c_dflt", 0); |
| assert_non_null(st->target); |
| assert_int_equal(lyd_validate(&(st->target), NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| st->source = lyd_new_path(NULL, st->ctx, "/merge-dflt:top/a", "a_val", 0); |
| assert_non_null(st->source); |
| tmp = lyd_new_path(st->source, st->ctx, "/merge-dflt:top/b", "b_val", 0); |
| assert_non_null(tmp); |
| assert_int_equal(lyd_validate(&(st->source), NULL, LYD_VALIDATE_PRESENT), LY_SUCCESS); |
| |
| assert_int_equal(lyd_merge(&st->target, st->source, LYD_MERGE_EXPLICIT), LY_SUCCESS); |
| |
| /* c should not be replaced, so c remains not default */ |
| assert_false(lyd_node_children(st->target, 0)->flags & LYD_DEFAULT); |
| } |
| |
| static void |
| test_leafrefs(void **state) |
| { |
| struct state *st = (*state); |
| const char *sch = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " list l {" |
| " key n;" |
| " leaf n { type string; }" |
| " leaf t { type string; }" |
| " leaf r { type leafref { path '/l/n'; } }}}"; |
| const char *trg = "<l xmlns=\"urn:x\"><n>a</n></l>" |
| "<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>"; |
| const char *src = "<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>" |
| "<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>"; |
| const char *res = "<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>" |
| "<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>" |
| "<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>"; |
| char *prt = NULL; |
| |
| assert_non_null(lys_parse_mem(st->ctx, sch, LYS_IN_YANG)); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, src, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->source)); |
| assert_non_null(st->source); |
| |
| assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, trg, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->target)); |
| assert_non_null(st->target); |
| |
| assert_int_equal(lyd_merge(&st->target, st->source, LYD_MERGE_DESTRUCT), LY_SUCCESS); |
| st->source = NULL; |
| |
| lyd_print_mem(&prt, st->target, LYD_XML, LYD_PRINT_WITHSIBLINGS); |
| assert_string_equal(prt, res); |
| free(prt); |
| } |
| |
| int |
| main(void) |
| { |
| const struct CMUnitTest tests[] = { |
| cmocka_unit_test_setup_teardown(test_batch, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_leaf, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_container, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_list, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_list2, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_case, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_dflt, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_dflt2, setup_dflt, teardown_dflt), |
| cmocka_unit_test_setup_teardown(test_leafrefs, setup_dflt, teardown_dflt), |
| }; |
| |
| return cmocka_run_group_tests(tests, NULL, NULL); |
| } |