| /** |
| * @file test_values.c |
| * @author Radek Krejci <rkrejci@cesnet.cz> |
| * @brief Cmocka tests for correct resolving of types and values of the data nodes. |
| * |
| * Copyright (c) 2016 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 <stdio.h> |
| #include <stdlib.h> |
| #include <setjmp.h> |
| #include <stdarg.h> |
| #include <cmocka.h> |
| |
| #include "tests/config.h" |
| #include "libyang.h" |
| |
| struct state { |
| struct ly_ctx *ctx; |
| struct lyd_node *dt; |
| char *data; |
| }; |
| |
| static int |
| setup_f(void **state) |
| { |
| struct state *st; |
| |
| (*state) = st = calloc(1, sizeof *st); |
| if (!st) { |
| fprintf(stderr, "Memory allocation error"); |
| return -1; |
| } |
| |
| /* libyang context */ |
| st->ctx = ly_ctx_new(NULL, 0); |
| if (!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_f(void **state) |
| { |
| struct state *st = (*state); |
| |
| lyd_free_withsiblings(st->dt); |
| ly_ctx_destroy(st->ctx, NULL); |
| free(st->data); |
| free(st); |
| (*state) = NULL; |
| |
| return 0; |
| } |
| |
| /* |
| * default values of integer types are allowed to be specified in decimal, octal and hexadecimal forms |
| */ |
| static void |
| test_default_int(void **state) |
| { |
| struct state *st = (*state); |
| const char *yang = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " leaf a { type int8; default 10; }" // decimal (10) |
| " leaf b { type int8; default 012; }" // octal (10) |
| " leaf c { type int8; default 0xa; }" // hexadecimal (10) |
| "}"; |
| const char *xml1 = "<a xmlns=\"urn:x\">012</a>"; // value is supposed to be 12, not 10 as in case of octal value |
| const char *xml2 = "<a xmlns=\"urn:x\">0xa</a>"; // error |
| const struct lys_module *mod; |
| |
| mod = lys_parse_mem(st->ctx, yang, LYS_IN_YANG); |
| assert_ptr_not_equal(mod, NULL); |
| assert_string_equal(mod->data->name, "a"); |
| assert_string_equal(((struct lys_node_leaf *)mod->data)->dflt, "10"); |
| assert_string_equal(mod->data->next->name, "b"); |
| assert_string_equal(((struct lys_node_leaf *)mod->data->next)->dflt, "10"); |
| assert_string_equal(mod->data->prev->name, "c"); |
| assert_string_equal(((struct lys_node_leaf *)mod->data->prev)->dflt, "10"); |
| |
| /* in contrast, octal and hexadecimal values are not allowed in data */ |
| st->dt = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_CONFIG); |
| assert_ptr_equal(st->dt, NULL); |
| assert_int_equal(ly_errno, LY_EVALID); |
| assert_int_equal(ly_vecode(st->ctx), LYVE_INVAL); |
| assert_string_equal(ly_errmsg(st->ctx), "Invalid value \"0xa\" in \"a\" element."); |
| |
| st->dt = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_CONFIG); |
| assert_ptr_not_equal(st->dt, NULL); |
| assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "12"); |
| } |
| |
| |
| /* |
| * Sometimes the default isn't stored in canonical form, so this ensures the default |
| * value is populated properly anyways |
| */ |
| static void |
| test_default_int_trusted(void **state) |
| { |
| struct state *st = (*state); |
| ly_ctx_destroy(st->ctx, NULL); |
| st->ctx = ly_ctx_new(NULL, LY_CTX_TRUSTED); |
| |
| const char *yang = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " leaf a { type int8; default 10; }" // decimal (10) |
| " leaf b { type int8; default 012; }" // octal (10) |
| " leaf c { type int8; default 0xa; }" // hexadecimal (10) |
| "}"; |
| const char *xml1 = "<a xmlns=\"urn:x\">12</a>"; |
| const struct lys_module *mod; |
| |
| mod = lys_parse_mem(st->ctx, yang, LYS_IN_YANG); |
| assert_ptr_not_equal(mod, NULL); |
| |
| st->dt = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_CONFIG); |
| assert_ptr_not_equal(st->dt, NULL); |
| assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "12"); |
| |
| assert_int_equal(lyd_validate(&st->dt, LYD_OPT_CONFIG, st->ctx), EXIT_SUCCESS); |
| } |
| |
| /* |
| * identityref and instance-identifiers values in XML are supposed to be converted into a JSON form where the prefixes |
| * are the names of the modules, not a generic prefixes as in XML |
| */ |
| static void |
| test_xmltojson_identityref(void **state) |
| { |
| struct state *st = (*state); |
| const char *yang1 = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " identity vehicle;" |
| " identity car { base vehicle; }" |
| "}"; |
| const char *yang2 = "module y {" |
| " namespace urn:y;" |
| " prefix y;" |
| " import x { prefix xpref; }" |
| " leaf y1 { type identityref { base xpref:vehicle; } }" |
| " leaf y2 { type leafref { path \"../y1\"; } }" |
| "}"; |
| const char *xml = "<y1 xmlns=\"urn:y\" xmlns:z=\"urn:x\">z:car</y1>" |
| "<y2 xmlns=\"urn:y\" xmlns:z=\"urn:x\">z:car</y2>"; |
| const char *result = "<y1 xmlns=\"urn:y\" xmlns:x=\"urn:x\">x:car</y1>" |
| "<y2 xmlns=\"urn:y\" xmlns:x=\"urn:x\">x:car</y2>"; |
| |
| assert_ptr_not_equal(lys_parse_mem(st->ctx, yang1, LYS_IN_YANG), NULL); |
| assert_ptr_not_equal(lys_parse_mem(st->ctx, yang2, LYS_IN_YANG), NULL); |
| |
| st->dt = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_CONFIG); |
| assert_ptr_not_equal(st->dt, NULL); |
| |
| lyd_print_mem(&st->data, st->dt, LYD_XML, LYP_WITHSIBLINGS); |
| assert_ptr_not_equal(st->data, NULL); |
| assert_string_equal(st->data, result); |
| } |
| |
| static void |
| test_xmltojson_identityref2(void **state) |
| { |
| struct state *st = (*state); |
| const char *yang = "module y {" |
| " namespace urn:y;" |
| " prefix y;" |
| " identity vehicle;" |
| " identity car { base vehicle; }" |
| " leaf y { type identityref { base y:vehicle; } default y:car; }" |
| "}"; |
| const char *result = "<y xmlns=\"urn:y\">car</y>"; |
| |
| assert_ptr_not_equal(lys_parse_mem(st->ctx, yang, LYS_IN_YANG), NULL); |
| |
| st->dt = NULL; |
| lyd_validate(&st->dt, LYD_OPT_CONFIG, st->ctx); |
| assert_ptr_not_equal(st->dt, NULL); |
| |
| lyd_print_mem(&st->data, st->dt, LYD_XML, LYP_WITHSIBLINGS | LYP_WD_ALL); |
| assert_ptr_not_equal(st->data, NULL); |
| assert_string_equal(st->data, result); |
| } |
| |
| static void |
| test_xmltojson_instanceid(void **state) |
| { |
| struct state *st = (*state); |
| const char *yang1 = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " leaf x { type string; }" |
| "}"; |
| const char *yang2 = "module y {" |
| " namespace urn:y;" |
| " prefix y;" |
| " leaf y1 { type instance-identifier; }" |
| " leaf y2 { type leafref { path \"../y1\"; } }" |
| "}"; |
| const char *xml = "<x xmlns=\"urn:x\">test</x>" |
| "<y1 xmlns=\"urn:y\" xmlns:z=\"urn:x\">/z:x</y1>" |
| "<y2 xmlns=\"urn:y\" xmlns:z=\"urn:x\">/z:x</y2>"; |
| const char *result = "<x xmlns=\"urn:x\">test</x>" |
| "<y1 xmlns=\"urn:y\" xmlns:x=\"urn:x\">/x:x</y1>" |
| "<y2 xmlns=\"urn:y\" xmlns:x=\"urn:x\">/x:x</y2>"; |
| |
| assert_ptr_not_equal(lys_parse_mem(st->ctx, yang1, LYS_IN_YANG), NULL); |
| assert_ptr_not_equal(lys_parse_mem(st->ctx, yang2, LYS_IN_YANG), NULL); |
| |
| st->dt = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_CONFIG); |
| assert_ptr_not_equal(st->dt, NULL); |
| |
| lyd_print_mem(&st->data, st->dt, LYD_XML, LYP_WITHSIBLINGS); |
| assert_ptr_not_equal(st->data, NULL); |
| assert_string_equal(st->data, result); |
| } |
| |
| static void |
| test_canonical(void **state) |
| { |
| struct state *st = (*state); |
| const char *yang = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " container x {" |
| " leaf-list a { type int8; }" |
| " leaf-list b { type int16; }" |
| " leaf-list c { type int32; }" |
| " leaf-list d { type int64; }" |
| " leaf-list e { type uint8; }" |
| " leaf-list f { type uint16; }" |
| " leaf-list g { type uint32; }" |
| " leaf-list h { type uint64; }" |
| " leaf-list i { type decimal64 { fraction-digits 2; } }" |
| " leaf-list j { type bits {" |
| " bit one { position 1; }" |
| " bit three { position 3; }" |
| " bit two { position 2; }" |
| " } }" |
| " leaf-list alr { type leafref { path ../a; } }" |
| " leaf-list blr { type leafref { path ../b; } }" |
| " leaf-list clr { type leafref { path ../c; } }" |
| " leaf-list dlr { type leafref { path ../d; } }" |
| " leaf-list elr { type leafref { path ../e; } }" |
| " leaf-list flr { type leafref { path ../f; } }" |
| " leaf-list glr { type leafref { path ../g; } }" |
| " leaf-list hlr { type leafref { path ../h; } }" |
| " leaf-list ilr { type leafref { path ../i; } }" |
| " leaf-list jlr { type leafref { path ../j; } }" |
| "} }"; |
| const char *input = "<x xmlns=\"urn:x\">" |
| "<a>+1</a><a>+0</a>" |
| "<b>+300</b><b>+0</b>" |
| "<c>+66000</c><c>+0</c>" |
| "<d>+4300000000</d><d>+0</d>" |
| "<e>+1</e><e>-0</e>" |
| "<f>+300</f><f>-0</f>" |
| "<g>+66000</g><g>-0</g>" |
| "<h>+4300000000</h><h>-0</h>" |
| "<i>1</i><i>+2</i><i>0</i><i>3.000000</i><i>0000004</i><i>4.1</i>" |
| "<j> three two</j><j>one two</j><j> two three one</j>" |
| "<alr>+1</alr><alr>+0</alr>" |
| "<blr>+300</blr><blr>+0</blr>" |
| "<clr>+66000</clr><clr>+0</clr>" |
| "<dlr>+4300000000</dlr><dlr>+0</dlr>" |
| "<elr>+1</elr><elr>-0</elr>" |
| "<flr>+300</flr><flr>-0</flr>" |
| "<glr>+66000</glr><glr>-0</glr>" |
| "<hlr>+4300000000</hlr><hlr>-0</hlr>" |
| "<ilr>1</ilr><ilr>+2</ilr><ilr>0</ilr><ilr>3.000000</ilr><ilr>0000004</ilr><ilr>4.1</ilr>" |
| "<jlr> three two</jlr><jlr>one two</jlr><jlr> two three one</jlr>" |
| "</x>"; |
| const char *result = "<x xmlns=\"urn:x\">" |
| "<a>1</a><a>0</a>" |
| "<b>300</b><b>0</b>" |
| "<c>66000</c><c>0</c>" |
| "<d>4300000000</d><d>0</d>" |
| "<e>1</e><e>0</e>" |
| "<f>300</f><f>0</f>" |
| "<g>66000</g><g>0</g>" |
| "<h>4300000000</h><h>0</h>" |
| "<i>1.0</i><i>2.0</i><i>0.0</i><i>3.0</i><i>4.0</i><i>4.1</i>" |
| "<j>two three</j><j>one two</j><j>one two three</j>" |
| "<alr>1</alr><alr>0</alr>" |
| "<blr>300</blr><blr>0</blr>" |
| "<clr>66000</clr><clr>0</clr>" |
| "<dlr>4300000000</dlr><dlr>0</dlr>" |
| "<elr>1</elr><elr>0</elr>" |
| "<flr>300</flr><flr>0</flr>" |
| "<glr>66000</glr><glr>0</glr>" |
| "<hlr>4300000000</hlr><hlr>0</hlr>" |
| "<ilr>1.0</ilr><ilr>2.0</ilr><ilr>0.0</ilr><ilr>3.0</ilr><ilr>4.0</ilr><ilr>4.1</ilr>" |
| "<jlr>two three</jlr><jlr>one two</jlr><jlr>one two three</jlr>" |
| "</x>"; |
| |
| assert_ptr_not_equal(lys_parse_mem(st->ctx, yang, LYS_IN_YANG), NULL); |
| st->dt = lyd_parse_mem(st->ctx, input, LYD_XML, LYD_OPT_CONFIG); |
| assert_ptr_not_equal(st->dt, NULL); |
| |
| lyd_print_mem(&st->data, st->dt, LYD_XML, LYP_WITHSIBLINGS); |
| assert_ptr_not_equal(st->data, NULL); |
| assert_string_equal(st->data, result); |
| } |
| |
| static void |
| test_validate_value(void **state) |
| { |
| struct state *st = (*state); |
| const struct lys_module *mod; |
| struct lys_node *node; |
| const char *yang = "module x {" |
| " namespace urn:x;" |
| " prefix x;" |
| " leaf target {" |
| " type string {" |
| " length 2..4;" |
| " pattern \'a*\';" |
| " }" |
| " }" |
| " leaf a {" |
| " type leafref {" |
| " path /x:target;" |
| " }" |
| " }" |
| " leaf b {" |
| " type int8 {" |
| " range -1..1;" |
| " }" |
| " }" |
| " leaf c {" |
| " type enumeration {" |
| " enum alfa;" |
| " }" |
| " }" |
| " leaf d {" |
| " type decimal64 {" |
| " fraction-digits 1;" |
| " }" |
| " }" |
| " leaf e {" |
| " type decimal64 {" |
| " fraction-digits 10;" |
| " }" |
| " }" |
| " leaf f {" |
| " type decimal64 {" |
| " fraction-digits 18;" |
| " }" |
| " }" |
| "}"; |
| |
| mod = lys_parse_mem(st->ctx, yang, LYS_IN_YANG); |
| assert_ptr_not_equal(mod, NULL); |
| |
| /* a */ |
| node = mod->data->next; |
| assert_int_equal(lyd_validate_value(node, NULL), EXIT_FAILURE); /* empty string is too short */ |
| assert_int_equal(lyd_validate_value(node, "a"), EXIT_FAILURE); /* a is still too short */ |
| assert_int_equal(lyd_validate_value(node, "bbb"), EXIT_FAILURE); /* does not match the pattern */ |
| assert_int_equal(lyd_validate_value(node, "aaaaa"), EXIT_FAILURE); /* too long */ |
| assert_int_equal(lyd_validate_value(node, "aaa"), EXIT_SUCCESS); /* ok */ |
| |
| /* b */ |
| node = node->next; |
| assert_int_equal(lyd_validate_value(node, "2"), EXIT_FAILURE); /* too high */ |
| assert_int_equal(lyd_validate_value(node, "-"), EXIT_FAILURE); /* does not match the type (yet) */ |
| assert_int_equal(lyd_validate_value(node, "-2"), EXIT_FAILURE); /* too low */ |
| assert_int_equal(lyd_validate_value(node, "0"), EXIT_SUCCESS); /* ok */ |
| |
| /* c */ |
| node = node->next; |
| assert_int_equal(lyd_validate_value(node, "a"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "al"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "alf"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "alfa"), EXIT_SUCCESS); /* ok */ |
| assert_int_equal(lyd_validate_value(node, "alfa "), EXIT_FAILURE); |
| |
| /* d */ |
| node = node->next; |
| assert_int_equal(lyd_validate_value(node, "-922337203685477580.9"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "-925337203685477580"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "922337203685477580.8"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "932337203685477580"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "-922337203685477580.8"), EXIT_SUCCESS); /* ok */ |
| assert_int_equal(lyd_validate_value(node, "922337203685477580.7"), EXIT_SUCCESS); /* ok */ |
| |
| /* e */ |
| node = node->next; |
| assert_int_equal(lyd_validate_value(node, "-922337203.6854775818"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "-9223372031"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "922337203.6854785807"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "1922337203"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "-922337203.6854775808"), EXIT_SUCCESS); /* ok */ |
| assert_int_equal(lyd_validate_value(node, "922337203.6854775807"), EXIT_SUCCESS); /* ok */ |
| |
| /* f */ |
| node = node->next; |
| assert_int_equal(lyd_validate_value(node, "-9.223372036854776808"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "-10"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "9.223372136854775807"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "11"), EXIT_FAILURE); |
| assert_int_equal(lyd_validate_value(node, "-9.223372036854775808"), EXIT_SUCCESS); /* ok */ |
| assert_int_equal(lyd_validate_value(node, "9.223372036854775807"), EXIT_SUCCESS); /* ok */ |
| } |
| |
| int main(void) |
| { |
| const struct CMUnitTest tests[] = { |
| cmocka_unit_test_setup_teardown(test_default_int, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_default_int_trusted, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_xmltojson_identityref, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_xmltojson_identityref2, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_xmltojson_instanceid, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_canonical, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_validate_value, setup_f, teardown_f),}; |
| |
| return cmocka_run_group_tests(tests, NULL, NULL); |
| } |