diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2a34739d3d..640bb1ec3d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
options: "-DENABLE_TESTS=ON",
packager: "sudo apt-get",
# no expect because stdout seems to be redirected
- packages: "libcmocka-dev libxxhash-dev",
+ packages: "libcmocka-dev libxxhash-dev libcbor-dev",
snaps: "",
build-cmd: "make"
}
@@ -36,7 +36,7 @@ jobs:
cc: "clang",
options: "-DENABLE_TESTS=ON",
packager: "sudo apt-get",
- packages: "libcmocka-dev libxxhash-dev",
+ packages: "libcmocka-dev libxxhash-dev libcbor-dev",
snaps: "",
build-cmd: "make"
}
@@ -47,7 +47,7 @@ jobs:
cc: "gcc",
options: "",
packager: "sudo apt-get",
- packages: "libcmocka-dev libxxhash-dev valgrind",
+ packages: "libcmocka-dev libxxhash-dev libcbor-dev valgrind",
snaps: "",
build-cmd: "make"
}
@@ -59,7 +59,7 @@ jobs:
options: "",
packager: "sudo apt-get",
# no valgrind because it does not support DWARF5 yet generated by clang 14
- packages: "libcmocka-dev libxxhash-dev",
+ packages: "libcmocka-dev libxxhash-dev libcbor-dev",
snaps: "",
build-cmd: "make"
}
@@ -70,7 +70,7 @@ jobs:
cc: "clang",
options: "-DENABLE_TESTS=ON -DPATH_EXPECT=",
packager: "brew",
- packages: "cmocka xxhash tcl-tk",
+ packages: "cmocka xxhash tcl-tk libcbor",
snaps: "",
build-cmd: "make"
}
@@ -81,7 +81,7 @@ jobs:
cc: "clang",
options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_TESTS=ON -DENABLE_VALGRIND_TESTS=OFF",
packager: "sudo apt-get",
- packages: "libcmocka-dev libxxhash-dev",
+ packages: "libcmocka-dev libxxhash-dev libcbor-dev",
snaps: "",
build-cmd: "make"
}
@@ -282,7 +282,7 @@ jobs:
prepare: |
echo "Installing dependencies..."
pkg update -f
- pkg install -y cmake cmocka xxhash bash git pcre2
+ pkg install -y cmake cmocka xxhash bash git pcre2 libcbor
run: |
set -e
@@ -308,7 +308,7 @@ jobs:
i386/ubuntu \
/bin/bash -c " \
apt-get update -q && \
- apt-get install -y -q git cmake gcc libcmocka-dev libxxhash-dev libpcre2-dev && \
+ apt-get install -y -q git cmake gcc libcmocka-dev libxxhash-dev libpcre2-dev libcbor-dev && \
mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=ON .. && \
make && \
@@ -338,7 +338,7 @@ jobs:
# install dependencies inside the emulated container
install: |
apt-get update -q -y
- apt-get install -q -y git cmake gcc libcmocka-dev libxxhash-dev libpcre2-dev
+ apt-get install -q -y git cmake gcc libcmocka-dev libxxhash-dev libpcre2-dev libcbor-dev
# run the build
run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd5592f3dc..ead8b1ea89 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,15 +59,15 @@ set(CMAKE_MACOSX_RPATH TRUE)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# set version of the project
-set(LIBYANG_MAJOR_VERSION 5)
-set(LIBYANG_MINOR_VERSION 8)
-set(LIBYANG_MICRO_VERSION 6)
+set(LIBYANG_MAJOR_VERSION 6)
+set(LIBYANG_MINOR_VERSION 2)
+set(LIBYANG_MICRO_VERSION 0)
set(LIBYANG_VERSION ${LIBYANG_MAJOR_VERSION}.${LIBYANG_MINOR_VERSION}.${LIBYANG_MICRO_VERSION})
# set version of the library
set(LIBYANG_MAJOR_SOVERSION 5)
-set(LIBYANG_MINOR_SOVERSION 5)
-set(LIBYANG_MICRO_SOVERSION 5)
+set(LIBYANG_MINOR_SOVERSION 7)
+set(LIBYANG_MICRO_SOVERSION 0)
set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION})
set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION})
@@ -149,6 +149,7 @@ set(libsrc
src/parser_yang.c
src/parser_yin.c
src/printer_schema.c
+ src/printer_sid.c
src/printer_yang.c
src/printer_yin.c
src/printer_tree.c
@@ -238,6 +239,7 @@ set(format_sources
src/*.h
src/plugins_exts/*
src/plugins_types/*)
+
#
# options
#
@@ -323,11 +325,30 @@ if(ENABLE_COVERAGE)
gen_coverage_enable(${ENABLE_TESTS})
endif()
+find_package(CBOR)
+if(CBOR_FOUND)
+ list(APPEND libsrc src/parser_cbor.c src/lcbor.c src/printer_cbor.c)
+ list(APPEND headers src/lcbor.h)
+ list(APPEND format_sources src/parser_cbor.c src/lcbor.h src/lcbor.c src/printer_cbor.c)
+else()
+ message(STATUS "libcbor not found, CBOR support disabled")
+endif()
+
if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
# enable before adding tests to let them detect that format checking is available - one of the tests is format checking
source_format_enable(0.77)
endif()
+if(ENABLE_FUZZ_TARGETS)
+ set(FUZZER "AFL" CACHE STRING "fuzzer type")
+ if(FUZZER STREQUAL "LibFuzzer")
+ if (NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ message(FATAL_ERROR "LibFuzzer works only with clang")
+ endif()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
+ endif()
+endif()
+
# check regex compatibility
check_include_file("regex.h" LY_HAVE_REGEX_H)
if(LY_HAVE_REGEX_H)
@@ -427,6 +448,17 @@ find_package(PCRE2 10.21 REQUIRED)
include_directories(${PCRE2_INCLUDE_DIRS})
target_link_libraries(yang ${PCRE2_LIBRARIES})
+# link libcbor if found
+if(CBOR_FOUND)
+ if(TARGET yangobj)
+ target_compile_definitions(yangobj PRIVATE ENABLE_CBOR_SUPPORT)
+ target_include_directories(yangobj PRIVATE ${CBOR_INCLUDE_DIR})
+ endif()
+ target_compile_definitions(yang PRIVATE ENABLE_CBOR_SUPPORT)
+ target_include_directories(yang PRIVATE ${CBOR_INCLUDE_DIR})
+ target_link_libraries(yang ${CBOR_LIBRARY})
+endif()
+
# XXHash include and library
find_package(XXHash)
if(XXHASH_FOUND)
@@ -477,16 +509,8 @@ endif()
if(ENABLE_TESTS)
enable_testing()
add_subdirectory(tests)
-endif()
-
-if(ENABLE_FUZZ_TARGETS)
- set(FUZZER "AFL" CACHE STRING "fuzzer type")
- if(FUZZER STREQUAL "LibFuzzer")
- if (NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
- message(FATAL_ERROR "LibFuzzer works only with clang")
- endif()
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
- endif()
+elseif(ENABLE_FUZZ_TARGETS AND NOT WIN32)
+ add_subdirectory(tests/fuzz)
endif()
# create coverage target for generating coverage reports
diff --git a/CMakeModules/FindCBOR.cmake b/CMakeModules/FindCBOR.cmake
new file mode 100644
index 0000000000..14478f3acf
--- /dev/null
+++ b/CMakeModules/FindCBOR.cmake
@@ -0,0 +1,37 @@
+# Try to find libcbor
+# Once done this will define
+#
+# Read-Only variables:
+# CBOR_FOUND - system has libcbor
+# CBOR_INCLUDE_DIR - the libcbor include directory
+# CBOR_LIBRARY - Link these to use libcbor
+
+find_path(CBOR_INCLUDE_DIR
+ NAMES
+ cbor.h
+ PATHS
+ /usr/include
+ /usr/local/include
+ /opt/local/include
+ /sw/include
+ ${CMAKE_INCLUDE_PATH}
+ ${CMAKE_INSTALL_PREFIX}/include
+)
+
+find_library(CBOR_LIBRARY
+ NAMES
+ cbor
+ libcbor
+ PATHS
+ /usr/lib
+ /usr/lib64
+ /usr/local/lib
+ /usr/local/lib64
+ /opt/local/lib
+ /sw/lib
+ ${CMAKE_LIBRARY_PATH}
+ ${CMAKE_INSTALL_PREFIX}/lib
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CBOR FOUND_VAR CBOR_FOUND REQUIRED_VARS CBOR_INCLUDE_DIR CBOR_LIBRARY)
diff --git a/README.md b/README.md
index 01884915b3..036318a0b7 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,10 @@ as well as YANG 1.1 ([RFC 7950](https://tools.ietf.org/html/rfc7950)).
Binary RPM or DEB packages of the latest release can be built locally using `apkg`, look into `README` in
the `distro` directory.
+### Mac OS
+
+libyang & yanglint can be installed using [homebrew](https://brew.sh/) with ```brew install libyang``` (community maintained)
+
## Requirements
### Unix Build Requirements
diff --git a/modules/ietf-sid-file@2024-07-31.yang b/modules/ietf-sid-file@2024-07-31.yang
new file mode 100644
index 0000000000..42bfd483f0
--- /dev/null
+++ b/modules/ietf-sid-file@2024-07-31.yang
@@ -0,0 +1,364 @@
+module ietf-sid-file {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-sid-file";
+ prefix sid;
+
+ import ietf-yang-types {
+ prefix yang;
+ reference
+ "RFC 6991: Common YANG Data Types";
+ }
+ import ietf-yang-structure-ext {
+ prefix sx;
+ reference
+ "RFC 8791: YANG Data Structure Extensions";
+ }
+
+ organization
+ "IETF CORE Working Group";
+
+ contact
+ "WG Web:
+
+ WG List:
+
+ Editor: Michel Veillette
+
+
+ Editor: Andy Bierman
+
+
+ Editor: Alexander Pelov
+
+
+ Editor: Ivaylo Petrov
+ ";
+
+ description
+ "This module defines the structure of the '.sid' files.
+
+ Each '.sid' file contains the mapping between each
+ string identifier defined by a YANG module and a
+ corresponding numeric value called a YANG SID.
+
+ The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
+ NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
+ 'MAY', and 'OPTIONAL' in this document are to be interpreted as
+ described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
+ they appear in all capitals, as shown here.
+
+ Copyright (c) 2024 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject to
+ the license terms contained in, the Revised BSD License set
+ forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 9595; see
+ the RFC itself for full legal notices.";
+
+ revision 2024-07-31 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 9595: YANG Schema Item iDentifier (YANG SID)";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '[0-9]{4}-[0-9]{2}-[0-9]{2}';
+ }
+ description
+ "Represents a date in YYYY-MM-DD format.";
+ }
+
+ typedef sid-file-version-identifier {
+ type uint32;
+ description
+ "Represents the version of a '.sid' file.";
+ }
+
+ typedef sid {
+ type uint64 {
+ range "0..9223372036854775807";
+ }
+ description
+ "YANG Schema Item iDentifier.";
+ reference
+ "RFC 9595: YANG Schema Item iDentifier (YANG SID)";
+ }
+
+ typedef schema-node-path {
+ type string {
+ pattern
+ '/[a-zA-Z_][a-zA-Z0-9\-_.]*:[a-zA-Z_][a-zA-Z0-9\-_.]*' +
+ '(/[a-zA-Z_][a-zA-Z0-9\-_.]*(:[a-zA-Z_][a-zA-Z0-9\-_.]*)?)*';
+ }
+ description
+ "A schema-node path is an absolute YANG schema-node
+ identifier as defined by the YANG ABNF rule
+ 'absolute-schema-nodeid', except that module names are used
+ instead of prefixes.
+
+ This string additionally follows the following rules:
+
+ - The leftmost (top-level) data node name is always in the
+ namespace-qualified form.
+ - Any subsequent schema-node name is in the
+ namespace-qualified form if the node is defined in a
+ module other than its parent node. Otherwise, the
+ simple form is used. No predicates are allowed.";
+ reference
+ "RFC 5234 (STD 68): Augmented BNF for Syntax Specifications:
+ ABNF
+ RFC 7950: The YANG 1.1 Data Modeling Language,
+ Section 6.5: Schema Node Identifier";
+ }
+
+ sx:structure sid-file {
+ uses sid-file-contents;
+ }
+
+ grouping sid-file {
+ description
+ "A grouping that contains a YANG container
+ representing the file structure of a '.sid' file.";
+
+ container sid-file {
+ description
+ "A wrapper container that together with the 'sx:structure'
+ extension marks the YANG data structures inside as not
+ being intended to be implemented as part of a
+ configuration datastore or as an operational state within
+ the server.";
+ uses sid-file-contents;
+ }
+ }
+
+ grouping sid-file-contents {
+ description
+ "A grouping that defines the contents of a container that
+ represents the file structure of a '.sid' file.";
+
+ leaf module-name {
+ type yang:yang-identifier;
+ mandatory true;
+ description
+ "Name of the YANG module associated with this
+ '.sid' file.";
+ }
+
+ leaf module-revision {
+ type revision-identifier;
+ description
+ "Revision of the YANG module associated with this '.sid'
+ file.
+ This leaf is not present if no revision statement is
+ defined in the YANG module.";
+ }
+
+ leaf sid-file-version {
+ type sid-file-version-identifier;
+ default 0;
+ description
+ "Optional leaf that specifies the version number of the
+ '.sid' file. '.sid' files and the version sequence are
+ specific to a given YANG module revision. This number
+ starts at zero when there is a new YANG module revision
+ and increases monotonically. This number can distinguish
+ updates to the '.sid' file - for instance, as the result
+ of new processing or reported errata.";
+ }
+
+ leaf sid-file-status {
+ type enumeration {
+ enum unpublished {
+ description
+ "This '.sid' file is unpublished (BCP 216) and is
+ also called a work-in-progress or workfile.
+ This may be when it accompanies an unpublished YANG
+ module or when only the '.sid' file itself is
+ unpublished.
+ The 'item' list MAY contain entries with a status
+ value of 'unstable'.";
+ reference
+ "RFC 8407 (BCP 216): Guidelines for Authors and
+ Reviewers of Documents Containing
+ YANG Data Models";
+ }
+ enum published {
+ description
+ "This '.sid' file is published. This status
+ applies to '.sid' files for published YANG modules.
+ The 'item' list MUST NOT contain entries with a
+ status value of 'unstable'.";
+ }
+ }
+ default "published";
+ description
+ "Optional leaf that specifies the status of the
+ '.sid' file.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Free-form meta-information about the generated file. It
+ might include a '.sid' file generation tool and time,
+ among other things.";
+ }
+
+ list dependency-revision {
+ key "module-name";
+
+ description
+ "Information about the revision used during the
+ '.sid' file generation of each dependency, i.e., each
+ YANG module that the YANG module associated with this
+ '.sid' file imported.";
+
+ leaf module-name {
+ type yang:yang-identifier;
+ description
+ "YANG module name of this dependency.";
+ }
+ leaf module-revision {
+ type revision-identifier;
+ mandatory true;
+ description
+ "Revision of the YANG module of this dependency.";
+ }
+ }
+
+ list assignment-range {
+ key "entry-point";
+ description
+ "YANG-SID Range(s) allocated to the YANG module
+ identified by 'module-name' and 'module-revision'.
+
+ - The first available value in the YANG-SID Range is
+ 'entry-point', and the last available value in the
+ range is ('entry-point' + size - 1).
+ - The YANG-SID Ranges specified by all
+ 'assignment-range' entries MUST NOT overlap.";
+
+ leaf entry-point {
+ type sid;
+ description
+ "Lowest YANG SID available for assignment.";
+ }
+
+ leaf size {
+ type uint64;
+ mandatory true;
+ description
+ "Number of YANG SIDs available for assignment.";
+ }
+ }
+
+ list item {
+ key "namespace identifier";
+ unique "sid";
+
+ description
+ "Each entry within this list defines the mapping between
+ a YANG item string identifier and a YANG SID. This list
+ MUST include a mapping entry for each YANG item defined
+ by the YANG module identified by 'module-name' and
+ 'module-revision'.";
+
+ leaf status {
+ type enumeration {
+ enum stable {
+ value 0;
+ description
+ "This SID allocation has been published as the
+ stable allocation for the given namespace and
+ identifier.";
+ }
+ enum unstable {
+ value 1;
+ description
+ "This SID allocation has been done during a
+ development process; it is not yet stable.";
+ }
+ enum obsolete {
+ value 2;
+ description
+ "This SID allocation is no longer in use. It is
+ recorded to avoid reallocation of its SID value.";
+ }
+ }
+ default "stable";
+ description
+ "The status field contains information about the
+ stability of the allocation. For each specific SID
+ value, over time it can only transition from
+ 'unstable' to 'stable', and possibly from 'stable' to
+ 'obsolete'.";
+ }
+
+ leaf namespace {
+ type enumeration {
+ enum module {
+ value 0;
+ description
+ "All module and submodule names share the same
+ global module identifier namespace.";
+ }
+ enum identity {
+ value 1;
+ description
+ "All identity names defined in a module and its
+ submodules share the same identity identifier
+ namespace.";
+ }
+ enum feature {
+ value 2;
+ description
+ "All feature names defined in a module and its
+ submodules share the same feature identifier
+ namespace.";
+ }
+ enum data {
+ value 3;
+ description
+ "The namespace for all data nodes, as defined in
+ YANG.";
+ }
+ }
+ description
+ "Namespace of the YANG item for this mapping entry.";
+ }
+
+ leaf identifier {
+ type union {
+ type yang:yang-identifier;
+ type schema-node-path;
+ }
+ description
+ "String identifier of the YANG item for this mapping
+ entry.
+
+ If the corresponding 'namespace' field is 'module',
+ 'feature', or 'identity', then this field MUST
+ contain a valid YANG identifier string.
+
+ If the corresponding 'namespace' field is 'data',
+ then this field MUST contain a valid schema-node
+ path.";
+ }
+
+ leaf sid {
+ type sid;
+ mandatory true;
+ description
+ "YANG SID assigned to the YANG item for this mapping
+ entry.";
+ }
+ }
+ }
+}
diff --git a/src/context.c b/src/context.c
index 9f063397ad..d9665ae63e 100644
--- a/src/context.c
+++ b/src/context.c
@@ -746,7 +746,7 @@ void
ly_ctx_new_change(struct ly_ctx *ctx)
{
const struct lys_module *mod;
- uint32_t i = ly_ctx_internal_modules_count(ctx), hash = 0;
+ uint32_t i = 0, hash = 0;
LY_ARRAY_COUNT_TYPE u;
/* change counter */
diff --git a/src/diff.c b/src/diff.c
index 525a741ec6..38551611fd 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -352,11 +352,9 @@ lyd_diff_dup(const struct lyd_node *node, enum lyd_diff_op op, struct lyd_node *
dup_parent = *dup;
node_parent = node;
sparent = parent ? parent->schema : NULL;
- while (lysc_data_parent(dup_parent->schema) &&
- !lyd_compare_schema_equal(lysc_data_parent(dup_parent->schema), sparent, 0)) {
- node_parent = node_parent->parent;
-
+ while (node_parent->parent && (!sparent || !lyd_compare_schema_equal(node_parent->parent->schema, sparent, 0))) {
/* duplicate the next parent */
+ node_parent = node_parent->parent;
LY_CHECK_RET(lyd_dup_single(node_parent, NULL, LYD_DUP_NO_META | LYD_DUP_WITH_FLAGS, &d));
/* connect the existing dup tree into the parent */
diff --git a/src/in.c b/src/in.c
index 5120d56115..2999ec24b4 100644
--- a/src/in.c
+++ b/src/in.c
@@ -46,6 +46,31 @@ ly_in_type(const struct ly_in *in)
return in->type;
}
+/**
+ * @brief Check whether @p count bytes can be read from the bounded input.
+ *
+ * @param[in] in Input handler.
+ * @param[in] count Number of bytes to be read.
+ * @return LY_SUCCESS if the read is within bounds.
+ * @return LY_EDENIED if reading @p count bytes would exceed the input length.
+ */
+static LY_ERR
+ly_in_check_read(const struct ly_in *in, size_t count)
+{
+ size_t offset;
+
+ if (!in->bounded) {
+ return LY_SUCCESS;
+ }
+
+ offset = in->current - in->start;
+ if ((offset > in->length) || (count > in->length - offset)) {
+ return LY_EDENIED;
+ }
+
+ return LY_SUCCESS;
+}
+
LIBYANG_API_DEF LY_ERR
ly_in_reset(struct ly_in *in)
{
@@ -78,6 +103,7 @@ ly_in_new_fd(int fd, struct ly_in **in)
(*in)->current = (*in)->start = (*in)->func_start = addr;
(*in)->line = 1;
(*in)->length = length;
+ (*in)->bounded = 1;
return LY_SUCCESS;
}
@@ -106,6 +132,7 @@ ly_in_fd(struct ly_in *in, int fd)
in->current = in->start = addr;
in->line = 1;
in->length = length;
+ in->bounded = 1;
}
return prev_fd;
@@ -179,6 +206,8 @@ ly_in_memory(struct ly_in *in, const char *str)
if (str) {
in->start = in->current = str;
in->line = 1;
+ in->length = 0;
+ in->bounded = 0;
}
return data;
@@ -299,12 +328,12 @@ ly_in_free(struct ly_in *in, ly_bool destroy)
LIBYANG_API_DEF LY_ERR
ly_in_read(struct ly_in *in, void *buf, size_t count)
{
+ size_t read_count;
+
LY_CHECK_ARG_RET(NULL, in, buf, LY_EINVAL);
- if (in->length && (in->length - (in->current - in->start) < count)) {
- /* EOF */
- return LY_EDENIED;
- }
+ read_count = (count && in->peeked) ? count - 1 : count;
+ LY_CHECK_RET(ly_in_check_read(in, read_count));
if (count && in->peeked) {
/* read the peeked byte */
@@ -328,13 +357,11 @@ ly_in_peek(struct ly_in *in, uint8_t *peek)
{
LY_CHECK_ARG_RET(NULL, in, peek, LY_EINVAL);
- if (in->length && (in->length - (in->current - in->start) < 1)) {
- /* EOF */
- return LY_EDENIED;
- } else if (in->peeked) {
+ if (in->peeked) {
/* unsupported */
return LY_ENOT;
}
+ LY_CHECK_RET(ly_in_check_read(in, 1));
memcpy(&in->peek, in->current, 1);
in->current += 1;
@@ -347,12 +374,12 @@ ly_in_peek(struct ly_in *in, uint8_t *peek)
LIBYANG_API_DEF LY_ERR
ly_in_skip(struct ly_in *in, size_t count)
{
+ size_t skip_count;
+
LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
- if (in->length && (in->length - (in->current - in->start) < count)) {
- /* EOF */
- return LY_EDENIED;
- }
+ skip_count = (count && in->peeked) ? count - 1 : count;
+ LY_CHECK_RET(ly_in_check_read(in, skip_count));
if (count && in->peeked) {
/* skip the peeked byte */
diff --git a/src/in.h b/src/in.h
index 78020bd956..0218df4685 100644
--- a/src/in.h
+++ b/src/in.h
@@ -162,9 +162,11 @@ LIBYANG_API_DECL FILE *ly_in_file(struct ly_in *in, FILE *f);
/**
* @brief Create input handler using memory to read data.
*
- * @param[in] str Pointer where to start reading data. The input data are expected to be NULL-terminated.
+ * The input data are expected to be valid (NULL-terminated for text formats).
* Note that in case the destroy argument of ::ly_in_free() is used, the input string is passed to free(),
- * so if it is really a static string, do not use the destroy argument!
+ * so if @p str is a static string, do not use the destroy argument!
+ *
+ * @param[in] str Data to read.
* @param[out] in Created input handler supposed to be passed to different ly*_parse() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
@@ -174,10 +176,12 @@ LIBYANG_API_DECL LY_ERR ly_in_new_memory(const char *str, struct ly_in **in);
/**
* @brief Get or change memory where the data are read from.
*
- * @param[in] in Input handler.
- * @param[in] str String containing the data to read. The input data are expected to be NULL-terminated.
+ * The input data are expected to be valid (NULL-terminated for text formats).
* Note that in case the destroy argument of ::ly_in_free() is used, the input string is passed to free(),
- * so if it is really a static string, do not use the destroy argument!
+ * so if @p str is a static string, do not use the destroy argument!
+ *
+ * @param[in] in Input handler.
+ * @param[in] str Data to read.
* @return Previous starting address to read data from. Note that the caller is responsible to free
* the data in case of changing string pointer @p str.
*/
diff --git a/src/in_internal.h b/src/in_internal.h
index 270c05a9e0..634553f79f 100644
--- a/src/in_internal.h
+++ b/src/in_internal.h
@@ -28,7 +28,8 @@ struct ly_in {
const char *current; /**< Current position in the input data */
const char *func_start; /**< Input data position when the last parser function was executed */
const char *start; /**< Input data start */
- size_t length; /**< mmap() length (if used) */
+ size_t length; /**< input data length (if bounded) */
+ ly_bool bounded; /**< whether @ref length limits reads from @ref start */
ly_bool peeked; /**< whether a byte was peeked */
uint8_t peek; /**< peeked byte, if any */
diff --git a/src/lcbor.c b/src/lcbor.c
new file mode 100644
index 0000000000..8997cce792
--- /dev/null
+++ b/src/lcbor.c
@@ -0,0 +1,117 @@
+/**
+ * @file lcbor.c
+ * @author MeherRushi
+ * @brief CBOR data parser for libyang (abstraction over libcbor)
+ *
+ * Copyright (c) 2026 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
+#include
+#include
+
+#include "in_internal.h"
+#include "lcbor.h"
+#include "log.h"
+#include "ly_common.h"
+
+const char *
+lycbor_token2str(enum cbor_type cbortype)
+{
+ switch (cbortype) {
+ case CBOR_TYPE_UINT:
+ return "unsigned integer";
+ case CBOR_TYPE_NEGINT:
+ return "negative integer";
+ case CBOR_TYPE_BYTESTRING:
+ return "byte string";
+ case CBOR_TYPE_STRING:
+ return "string";
+ case CBOR_TYPE_ARRAY:
+ return "array";
+ case CBOR_TYPE_MAP:
+ return "map";
+ case CBOR_TYPE_TAG:
+ return "tag";
+ case CBOR_TYPE_FLOAT_CTRL:
+ return "decimals and special values (true, false, nil, ...)";
+ }
+
+ return "";
+}
+
+void
+lycbor_ctx_free(struct lycbor_ctx *cborctx)
+{
+ if (cborctx) {
+ ly_log_location_revert(0, 0, 1);
+
+ if (cborctx->cbor_data) {
+ cbor_decref(&cborctx->cbor_data);
+ }
+ free(cborctx);
+ }
+}
+
+/**
+ * @brief Detect CBOR format variant from input data.
+ *
+ * @param[in] in Input structure to analyze.
+ * @param[out] format Detected format.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_detect_format(struct ly_in *in, enum lyd_cbor_format *format)
+{
+ /* Simple heuristic: try to parse as CBOR and examine structure */
+ /* For now, default to named format */
+ (void)in;
+ *format = LYD_CBOR_NAMED;
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lycbor_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lycbor_ctx **cborctx_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lycbor_ctx *cborctx;
+ struct cbor_load_result result = {0};
+ enum lyd_cbor_format format;
+
+ assert(ctx && in && cborctx_p);
+
+ LY_CHECK_RET(lydcbor_detect_format(in, &format));
+
+ /* Allocate and initialize CBOR context */
+ cborctx = calloc(1, sizeof *cborctx);
+ LY_CHECK_ERR_RET(!cborctx, LOGMEM(ctx), LY_EMEM);
+ cborctx->ctx = ctx;
+ cborctx->in = in;
+ cborctx->format = format;
+
+ /* input line logging */
+ ly_log_location(NULL, NULL, in);
+
+ /* load and parse CBOR data */
+ cborctx->cbor_data = cbor_load((cbor_data)in->current, in->length, &result);
+ if (!cborctx->cbor_data) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Failed to parse CBOR data.");
+ free(cborctx);
+ return LY_EVALID;
+ }
+ if (result.error.code != CBOR_ERR_NONE) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "CBOR parsing error (code %d).", result.error.code);
+ cbor_decref(&cborctx->cbor_data);
+ free(cborctx);
+ return LY_EVALID;
+ }
+
+ *cborctx_p = cborctx;
+ return ret;
+}
diff --git a/src/lcbor.h b/src/lcbor.h
new file mode 100644
index 0000000000..f31465a8be
--- /dev/null
+++ b/src/lcbor.h
@@ -0,0 +1,77 @@
+/**
+ * @file lcbor.h
+ * @author MeherRushi
+ * @brief CBOR data parser routines for libyang (abstraction over libcbor)
+ *
+ * Copyright (c) 2026 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
+ */
+
+#ifndef LY_CBOR_H_
+#define LY_CBOR_H_
+
+#include
+#include
+/* using libcbor as the low-level parser */
+#include
+
+#include "log.h"
+#include "set.h"
+
+struct ly_ctx;
+struct ly_in;
+
+/**
+ * @brief CBOR format variants for different encoding schemes
+ */
+enum lyd_cbor_format {
+ LYD_CBOR_NAMED, /**< CBOR with named identifiers (JSON-like) */
+ LYD_CBOR_SID /**< CBOR with Schema Item identifiers (future implementation) */
+};
+
+struct lycbor_ctx {
+ const struct ly_ctx *ctx;
+ struct ly_in *in; /** input structure */
+
+ cbor_item_t *cbor_data; /**< parsed CBOR data */
+
+ enum lyd_cbor_format format; /**< CBOR format variant */
+
+ struct {
+ cbor_item_t *cbor_data; /**< parsed CBOR data */
+ enum lyd_cbor_format format; /**< CBOR format variant */
+ const char *input;
+ } backup;
+};
+
+/**
+ * @brief Get a human-readable name for a CBOR type.
+ *
+ * @param[in] cbortype CBOR type.
+ * @return String representation of the CBOR type.
+ */
+const char *lycbor_token2str(enum cbor_type cbortype);
+
+/**
+ * @brief Create new CBOR context for parsing.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] in CBOR string data to parse.
+ * @param[out] cborctx New CBOR parser context containing parsed CBOR data.
+ * @return LY_ERR value.
+ */
+LY_ERR lycbor_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lycbor_ctx **cborctx);
+
+/**
+ * @brief Free CBOR context.
+ *
+ * @param[in] cborctx CBOR context to free.
+ */
+void lycbor_ctx_free(struct lycbor_ctx *cborctx);
+
+#endif /* LY_CBOR_H_ */
diff --git a/src/log.c b/src/log.c
index 9f5db98e7d..f006d058ec 100644
--- a/src/log.c
+++ b/src/log.c
@@ -112,6 +112,8 @@ ly_strvecode(LY_VECODE vecode)
return "XML syntax error";
case LYVE_SYNTAX_JSON:
return "JSON syntax error";
+ case LYVE_SYNTAX_CBOR:
+ return "CBOR syntax error";
case LYVE_DATA:
return "YANG data error";
case LYVE_OTHER:
diff --git a/src/log.h b/src/log.h
index 711b062116..9b0692f755 100644
--- a/src/log.h
+++ b/src/log.h
@@ -286,6 +286,7 @@ typedef enum {
LYVE_SEMANTICS, /**< generic semantic error */
LYVE_SYNTAX_XML, /**< XML-related syntax error */
LYVE_SYNTAX_JSON, /**< JSON-related syntax error */
+ LYVE_SYNTAX_CBOR, /**< CBOR-related syntax error */
LYVE_DATA, /**< YANG data does not reflect some of the module restrictions */
LYVE_OTHER /**< Unknown error */
diff --git a/src/ly_common.c b/src/ly_common.c
index 91a6c4e7a2..ad7ba00c32 100644
--- a/src/ly_common.c
+++ b/src/ly_common.c
@@ -1957,122 +1957,52 @@ ly_parse_nodeid(const char **id, const char **prefix, uint32_t *prefix_len, cons
}
LY_ERR
-ly_parse_instance_predicate(const char **pred, uint32_t limit, LYD_FORMAT format, const char **prefix, uint32_t *prefix_len,
- const char **id, uint32_t *id_len, const char **value, uint32_t *value_len, const char **errmsg)
+ly_val_get_quot(const struct ly_ctx *ctx, const char *value, char *quot)
{
- LY_ERR ret = LY_EVALID;
- const char *in = *pred;
- uint32_t offset = 1;
- uint8_t expr = 0; /* 0 - position predicate; 1 - leaf-list-predicate; 2 - key-predicate */
- char quot;
-
- assert(in[0] == '[');
-
- *prefix = *id = *value = NULL;
- *prefix_len = *id_len = *value_len = 0;
+ /* try ' */
+ *quot = '\'';
+ if (!strchr(value, *quot)) {
+ return LY_SUCCESS;
+ }
- /* leading *WSP */
- for ( ; isspace(in[offset]); offset++) {}
+ /* try " */
+ *quot = '\"';
+ if (!strchr(value, *quot)) {
+ return LY_SUCCESS;
+ }
- if (isdigit(in[offset])) {
- /* pos: "[" *WSP positive-integer-value *WSP "]" */
- if (in[offset] == '0') {
- /* zero */
- *errmsg = "The position predicate cannot be zero.";
- goto error;
- }
+ /* no valid quotes */
+ LOGERR(ctx, LY_EINVAL, "Invalid value with both ' and \" characters, unable to put in quotes.");
+ return LY_EINVAL;
+}
- /* positive-integer-value */
- *value = &in[offset++];
- for ( ; isdigit(in[offset]); offset++) {}
- *value_len = &in[offset] - *value;
-
- } else if (in[offset] == '.') {
- /* leaf-list-predicate: "[" *WSP "." *WSP "=" *WSP quoted-string *WSP "]" */
- *id = &in[offset];
- *id_len = 1;
- offset++;
- expr = 1;
- } else if (in[offset] == '-') {
- /* typically negative value */
- *errmsg = "Invalid instance predicate format (negative position or invalid node-identifier).";
- goto error;
- } else {
- /* key-predicate: "[" *WSP node-identifier *WSP "=" *WSP quoted-string *WSP "]" */
- in = &in[offset];
- if (ly_parse_nodeid(&in, prefix, prefix_len, id, id_len)) {
- *errmsg = "Invalid node-identifier.";
- goto error;
- }
- if ((format == LYD_XML) && !(*prefix)) {
- /* all node names MUST be qualified with explicit namespace prefix */
- *errmsg = "Missing prefix of a node name.";
- goto error;
- }
- offset = in - *pred;
- in = *pred;
- expr = 2;
- }
+LY_ERR
+ly_append_str(char **str, uint32_t *size, uint32_t *used, const char *format, ...)
+{
+ int p;
+ va_list ap;
- if (expr) {
- /* *WSP "=" *WSP quoted-string *WSP "]" */
- for ( ; isspace(in[offset]); offset++) {}
+ va_start(ap, format);
- if (in[offset] != '=') {
- if (expr == 1) {
- *errmsg = "Unexpected character instead of \'=\' in leaf-list-predicate.";
- } else { /* 2 */
- *errmsg = "Unexpected character instead of \'=\' in key-predicate.";
- }
- goto error;
- }
- offset++;
- for ( ; isspace(in[offset]); offset++) {}
+ /* try to append the string */
+ p = vsnprintf(*str ? *str + *used : NULL, *size - *used, format, ap);
- /* quoted-string */
- quot = in[offset++];
- if ((quot != '\'') && (quot != '\"')) {
- *errmsg = "String value is not quoted.";
- goto error;
- }
- *value = &in[offset];
- for ( ; offset < limit && (in[offset] != quot || (offset && in[offset - 1] == '\\')); offset++) {}
- if (in[offset] == quot) {
- *value_len = &in[offset] - *value;
- offset++;
- } else {
- *errmsg = "Value is not terminated quoted-string.";
- goto error;
- }
- }
+ if ((unsigned)p >= *size - *used) {
+ /* realloc */
+ *str = ly_realloc(*str, *size + p + 1);
+ LY_CHECK_ERR_RET(!*str, LOGMEM(NULL), LY_EMEM);
+ *size += p + 1;
- /* *WSP "]" */
- for ( ; isspace(in[offset]); offset++) {}
- if (in[offset] != ']') {
- if (expr == 0) {
- *errmsg = "Predicate (pos) is not terminated by \']\' character.";
- } else if (expr == 1) {
- *errmsg = "Predicate (leaf-list-predicate) is not terminated by \']\' character.";
- } else { /* 2 */
- *errmsg = "Predicate (key-predicate) is not terminated by \']\' character.";
- }
- goto error;
- }
- offset++;
+ /* restart ap */
+ va_end(ap);
+ va_start(ap, format);
- if (offset <= limit) {
- *pred = &in[offset];
- return LY_SUCCESS;
+ /* print */
+ p = vsnprintf(*str + *used, *size - *used, format, ap);
}
- /* we read after the limit */
- *errmsg = "Predicate is incomplete.";
- *prefix = *id = *value = NULL;
- *prefix_len = *id_len = *value_len = 0;
- offset = limit;
- ret = LY_EINVAL;
+ va_end(ap);
-error:
- *pred = &in[offset];
- return ret;
+ *used += p;
+ return LY_SUCCESS;
}
diff --git a/src/ly_common.h b/src/ly_common.h
index 5e5f629e79..e179914cb8 100644
--- a/src/ly_common.h
+++ b/src/ly_common.h
@@ -805,27 +805,26 @@ LY_ERR ly_parse_uint(const char *val_str, uint32_t val_len, uint64_t max, int ba
LY_ERR ly_parse_nodeid(const char **id, const char **prefix, uint32_t *prefix_len, const char **name, uint32_t *name_len);
/**
- * @brief parse instance-identifier's predicate, supports key-predicate, leaf-list-predicate and pos rules from YANG ABNF Grammar.
- *
- * @param[in,out] pred Predicate string (including the leading '[') to parse. The string is updated according to what was parsed
- * (even for error case, so it can be used to determine which substring caused failure).
- * @param[in] limit Limiting length of the @p pred. Function expects NULL terminated string which is not overread.
- * The limit value is not checked with each character, so it can be overread and the failure is detected later.
- * @param[in] format Input format of the data containing the @p pred.
- * @param[out] prefix Start of the node-identifier's prefix if any, NULL in case of pos or leaf-list-predicate rules.
- * @param[out] prefix_len Length of the parsed @p prefix.
- * @param[out] id Start of the node-identifier's identifier string, NULL in case of pos rule, "." in case of leaf-list-predicate rule.
- * @param[out] id_len Length of the parsed @p id.
- * @param[out] value Start of the quoted-string (without quotation marks), not NULL in case of success.
- * @param[out] value_len Length of the parsed @p value.
- * @param[out] errmsg Error message string in case of error.
- * @return LY_SUCCESS in case a complete predicate was parsed.
- * @return LY_EVALID in case of invalid predicate form.
- * @return LY_EINVAL in case of reaching @p limit when parsing @p pred.
- */
-LY_ERR ly_parse_instance_predicate(const char **pred, uint32_t limit, LYD_FORMAT format,
- const char **prefix, uint32_t *prefix_len, const char **id, uint32_t *id_len,
- const char **value, uint32_t *value_len, const char **errmsg);
+ * @brief Get suitable quotes for a value for use in an (X)Path expression.
+ *
+ * @param[in] ctx Context to use.
+ * @param[in] value Value to quote.
+ * @param[out] quot Quoting character.
+ * @return LY_ERR value.
+ */
+LY_ERR ly_val_get_quot(const struct ly_ctx *ctx, const char *value, char *quot);
+
+/**
+ * @brief Append a string to a dynamic string variable.
+ *
+ * @param[in,out] str String to use.
+ * @param[in,out] size String size.
+ * @param[in,out] used String used size excluding terminating zero. If NULL, 0 is assumed.
+ * @param[in] format Message format.
+ * @param[in] ... Message format arguments.
+ * @return LY_ERR value.
+ */
+LY_ERR ly_append_str(char **str, uint32_t *size, uint32_t *used, const char *format, ...);
/**
* @brief mmap(2) wrapper to map input files into memory to unify parsing.
diff --git a/src/ly_config.h.in b/src/ly_config.h.in
index 7cce68004c..0f0212290e 100644
--- a/src/ly_config.h.in
+++ b/src/ly_config.h.in
@@ -40,9 +40,6 @@
/** YANG module dir */
#define LY_YANG_MODULE_DIR "@YANG_MODULE_DIR@"
-/** lib source dir */
-#define LY_SRC_DIR "@CMAKE_CURRENT_SOURCE_DIR@"
-
/** atomic compiler operations, to be able to use uint32_t */
#ifndef _WIN32
# define LY_ATOMIC_INC_BARRIER(var) __sync_fetch_and_add(&(var), 1)
diff --git a/src/lyb.h b/src/lyb.h
index 99408893fe..fff8e00c25 100644
--- a/src/lyb.h
+++ b/src/lyb.h
@@ -123,10 +123,12 @@ struct lylyb_parse_ctx {
struct ly_in *in; /**< input structure */
uint8_t buf; /**< read leftover rightmost bits from in */
uint8_t buf_bits; /**< cached buf bit count */
+
+ uint32_t depth; /**< current node depth (nesting level) */
};
/**< current LYB format version */
-#define LYB_HEADER_VERSION_NUM 0x1
+#define LYB_HEADER_VERSION_NUM 0x2
/**< LYB format version reserved bit size */
#define LYB_HEADER_VERSION_BITS 3
diff --git a/src/parser_cbor.c b/src/parser_cbor.c
new file mode 100644
index 0000000000..b0a119c18d
--- /dev/null
+++ b/src/parser_cbor.c
@@ -0,0 +1,1644 @@
+/**
+ * @file parser_cbor.c
+ * @author Meher Rushi
+ * @brief CBOR data parser for libyang
+ *
+ * Copyright (c) 2026 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 _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include "compat.h"
+#include "context.h"
+#include "dict.h"
+#include "in_internal.h"
+#include "lcbor.h"
+#include "log.h"
+#include "ly_common.h"
+#include "parser_data.h"
+#include "parser_internal.h"
+#include "plugins_exts.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+#include "tree_schema_internal.h"
+#include "validation.h"
+
+/**
+ * @brief Free the CBOR data parser context.
+ *
+ * CBOR implementation of lyd_ctx_free_clb().
+ */
+static void
+lyd_cbor_ctx_free(struct lyd_ctx *lydctx)
+{
+ struct lyd_cbor_ctx *ctx = (struct lyd_cbor_ctx *)lydctx;
+
+ if (lydctx) {
+ lyd_ctx_free(lydctx);
+ ly_set_erase(&ctx->ext_node, NULL);
+ lycbor_ctx_free(ctx->cborctx);
+ free(ctx);
+ }
+}
+
+/**
+ * @brief Parse CBOR member-name as [\@][prefix:][name]
+ *
+ * \@ - metadata flag, maps to 1 in @p is_meta_p
+ * prefix - name of the module of the data node
+ * name - name of the data node
+ *
+ * All the output parameters are mandatory. Function only parses the member-name.
+ *
+ * @param[in] value String to parse
+ * @param[in] value_len Length of the @p value.
+ * @param[out] name_p Pointer to the beginning of the parsed name.
+ * @param[out] name_len_p Pointer to the length of the parsed name.
+ * @param[out] prefix_p Pointer to the beginning of the parsed prefix. If the member-name does not contain prefix, result is NULL.
+ * @param[out] prefix_len_p Pointer to the length of the parsed prefix. If the member-name does not contain prefix, result is 0.
+ * @param[out] is_meta_p Pointer to the metadata flag, set to 1 if the member-name contains \@, 0 otherwise.
+ */
+static void
+lydcbor_parse_name(const char *value, size_t value_len, const char **name_p, size_t *name_len_p, const char **prefix_p,
+ size_t *prefix_len_p, ly_bool *is_meta_p)
+{
+ const char *name, *prefix = NULL;
+ size_t name_len, prefix_len = 0;
+ ly_bool is_meta = 0;
+
+ name = memchr(value, ':', value_len);
+ if (name != NULL) {
+ prefix = value;
+ if (*prefix == '@') {
+ is_meta = 1;
+ prefix++;
+ }
+ prefix_len = name - prefix;
+ name++;
+ name_len = value_len - (prefix_len + 1) - is_meta;
+ } else {
+ name = value;
+ if (name[0] == '@') {
+ is_meta = 1;
+ name++;
+ }
+ name_len = value_len - is_meta;
+ }
+
+ *name_p = name;
+ *name_len_p = name_len;
+ *prefix_p = prefix;
+ *prefix_len_p = prefix_len;
+ *is_meta_p = is_meta;
+}
+
+/**
+ * @brief Get correct prefix (module_name) inside the @p node.
+ *
+ * @param[in] node Data node to get inherited prefix.
+ * @param[in] local_prefix Local prefix to replace the inherited prefix.
+ * @param[in] local_prefix_len Length of the @p local_prefix string. In case of 0, the inherited prefix is taken.
+ * @param[out] prefix_p Pointer to the resulting prefix string.
+ * @param[out] prefix_len_p Pointer to the length of the resulting @p prefix_p string.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_get_node_prefix(struct lyd_node *node, const char *local_prefix, size_t local_prefix_len, const char **prefix_p,
+ size_t *prefix_len_p)
+{
+ struct lyd_node_opaq *onode;
+ const char *module_name = NULL;
+
+ assert(prefix_p && prefix_len_p);
+
+ if (local_prefix_len) {
+ *prefix_p = local_prefix;
+ *prefix_len_p = local_prefix_len;
+ return LY_SUCCESS;
+ }
+
+ while (node) {
+ if (node->schema) {
+ module_name = node->schema->module->name;
+ break;
+ }
+ onode = (struct lyd_node_opaq *)node;
+ if (onode->name.module_name) {
+ module_name = onode->name.module_name;
+ break;
+ } else if (onode->name.prefix) {
+ module_name = onode->name.prefix;
+ break;
+ }
+ node = lyd_parent(node);
+ }
+
+ *prefix_p = module_name;
+ *prefix_len_p = ly_strlen(module_name);
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Skip the current CBOR item based on its type.
+ *
+ * @param[in] cborctx CBOR context.
+ * @param[in] item CBOR item to skip.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_data_skip(struct lycbor_ctx *cborctx)
+{
+ (void)cborctx;
+ /* In CBOR, items are already parsed, so skipping is implicit */
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Get schema node corresponding to the input parameters.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] is_attr Flag if the reference to the node is an attribute.
+ * @param[in] prefix Requested node's prefix (module name).
+ * @param[in] prefix_len Length of the @p prefix.
+ * @param[in] name Requested node's name.
+ * @param[in] name_len Length of the @p name.
+ * @param[in] parent Parent of the node being processed.
+ * @param[out] snode Found schema node corresponding to the input parameters.
+ * @param[out] ext Extension instance that provided @p snode, if any.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the whole object was parsed (skipped or as an extension).
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lydcbor_get_snode(struct lyd_cbor_ctx *lydctx, ly_bool is_attr, const char *prefix, size_t prefix_len, const char *name,
+ size_t name_len, struct lyd_node *parent, const struct lysc_node **snode, struct lysc_ext_instance **ext)
+{
+ LY_ERR r;
+ struct lys_module *mod = NULL;
+ const struct lysc_node *sparent;
+ uint32_t getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
+
+ *snode = NULL;
+ if (ext) {
+ *ext = NULL;
+ }
+
+ /* try to find parent schema node */
+ if (parent && parent->schema) {
+ sparent = parent->schema;
+ } else {
+ sparent = NULL;
+ }
+ if (sparent && (sparent->nodetype & LYD_NODE_ANY)) {
+ if (!prefix_len) {
+ /* inherit the module */
+ mod = sparent->module;
+ }
+
+ /* do not search in children */
+ sparent = NULL;
+ }
+
+ if (!prefix_len) {
+ prefix = NULL;
+ }
+ r = lys_find_child_node(parent ? LYD_CTX(parent) : lydctx->cborctx->ctx, sparent, mod, prefix, prefix_len,
+ LY_VALUE_CBOR, NULL, name, name_len, getnext_opts, snode, ext);
+ LY_CHECK_RET(r && (r != LY_ENOT), r);
+
+ if (!r) {
+ /* check that schema node is valid and can be used */
+ LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
+ return LY_SUCCESS;
+ }
+
+ /* generate error, find the module */
+ if (prefix_len) {
+ mod = ly_ctx_get_module_implemented2(parent ? LYD_CTX(parent) : lydctx->cborctx->ctx, prefix, prefix_len);
+ } else if (parent) {
+ if (parent->schema) {
+ mod = parent->schema->module;
+ }
+ } else if (!(lydctx->int_opts & LYD_INTOPT_ANY)) {
+ LOGVAL(lydctx->cborctx->ctx, parent, LYVE_SYNTAX,
+ "Top-level CBOR object member \"%.*s\" must be namespace-qualified.",
+ (int)(is_attr ? name_len + 1 : name_len), is_attr ? name - 1 : name);
+ return LY_EVALID;
+ }
+ if (!(lydctx->parse_opts & LYD_PARSE_STRICT)) {
+ return LY_SUCCESS;
+ }
+
+ if (!mod) {
+ LOGVAL(lydctx->cborctx->ctx, parent, LYVE_REFERENCE,
+ "No module named \"%.*s\" in the context.", (int)prefix_len, prefix);
+ return LY_EVALID;
+ }
+
+ if (sparent) {
+ LOGVAL(lydctx->cborctx->ctx, parent, LYVE_REFERENCE,
+ "Node \"%.*s\" not found as a child of \"%s\" node.",
+ (int)name_len, name, sparent->name);
+ } else {
+ LOGVAL(lydctx->cborctx->ctx, parent, LYVE_REFERENCE,
+ "Node \"%.*s\" not found in the \"%s\" module.",
+ (int)name_len, name, mod->name);
+ }
+ return LY_EVALID;
+}
+
+/**
+ * @brief Check if CBOR item is null/undefined.
+ *
+ * @param[in] item CBOR item to check.
+ * @return 1 if null/undefined, 0 otherwise.
+ */
+static ly_bool
+lydcbor_is_null(const cbor_item_t *item)
+{
+ if (!item) {
+ return 1;
+ }
+
+ if (cbor_isa_float_ctrl(item)) {
+ if (cbor_float_get_width(item) == CBOR_FLOAT_0) {
+ uint8_t ctrl = cbor_ctrl_value(item);
+
+ if ((ctrl == 22) || (ctrl == 23)) { /* null or undefined */
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Get the hint for the data type parsers according to the current CBOR type.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] item CBOR item.
+ * @param[out] type_hint_p Pointer to the variable to store the result.
+ * @return LY_SUCCESS in case of success.
+ * @return LY_EINVAL in case of invalid CBOR type.
+ */
+static LY_ERR
+lydcbor_value_type_hint(struct lyd_cbor_ctx *lydctx, const cbor_item_t *item, uint32_t *type_hint_p)
+{
+ enum cbor_type type;
+
+ *type_hint_p = 0;
+
+ if (!item) {
+ return LY_EINVAL;
+ }
+
+ type = cbor_typeof(item);
+
+ if (type == CBOR_TYPE_ARRAY) {
+ /* check for [null] */
+ if (cbor_array_size(item) == 1) {
+ cbor_item_t **handle = cbor_array_handle(item);
+
+ if (handle && lydcbor_is_null(handle[0])) {
+ *type_hint_p = LYD_VALHINT_EMPTY;
+ return LY_SUCCESS;
+ }
+ }
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_SYNTAX, "Expected CBOR value or [null], but array found.");
+ return LY_EINVAL;
+ } else if (type == CBOR_TYPE_STRING) {
+ *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
+ } else if ((type == CBOR_TYPE_UINT) || (type == CBOR_TYPE_NEGINT)) {
+ *type_hint_p = LYD_VALHINT_DECNUM;
+ } else if (type == CBOR_TYPE_FLOAT_CTRL) {
+ if (cbor_float_ctrl_is_ctrl(item)) {
+ uint8_t ctrl = cbor_ctrl_value(item);
+
+ if ((ctrl == CBOR_CTRL_TRUE) || (ctrl == CBOR_CTRL_FALSE)) {
+ *type_hint_p = LYD_VALHINT_BOOLEAN;
+ } else if (ctrl == CBOR_CTRL_NULL) {
+ *type_hint_p = 0;
+ } else {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_SYNTAX, "Unexpected CBOR control value.");
+ return LY_EINVAL;
+ }
+ } else {
+ *type_hint_p = LYD_VALHINT_DECNUM;
+ }
+ } else {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_SYNTAX, "Unexpected CBOR data type.");
+ return LY_EINVAL;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Convert a CBOR item to a string representation.
+ *
+ * @param[in] item CBOR item to convert.
+ * @param[out] str_val String value (allocated, caller must free).
+ * @param[out] str_len String length.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_item_to_string(const cbor_item_t *item, char **str_val, size_t *str_len)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ assert(item && str_val && str_len);
+ *str_val = NULL;
+ *str_len = 0;
+
+ switch (cbor_typeof(item)) {
+ case CBOR_TYPE_UINT: {
+ uint64_t val = cbor_get_int(item);
+ int len = snprintf(NULL, 0, "%" PRIu64, val);
+
+ if (len < 0) {
+ return LY_ESYS;
+ }
+ *str_val = malloc(len + 1);
+ LY_CHECK_ERR_RET(!*str_val, LOGMEM(NULL), LY_EMEM);
+ sprintf(*str_val, "%" PRIu64, val);
+ *str_len = len;
+ break;
+ }
+ case CBOR_TYPE_NEGINT: {
+ int64_t val = -1 - (int64_t)cbor_get_int(item);
+ int len = snprintf(NULL, 0, "%" PRId64, val);
+
+ if (len < 0) {
+ return LY_ESYS;
+ }
+ *str_val = malloc(len + 1);
+ LY_CHECK_ERR_RET(!*str_val, LOGMEM(NULL), LY_EMEM);
+ sprintf(*str_val, "%" PRId64, val);
+ *str_len = len;
+ break;
+ }
+ case CBOR_TYPE_BYTESTRING:
+ *str_len = cbor_bytestring_length(item);
+ *str_val = malloc(*str_len + 1);
+ LY_CHECK_ERR_RET(!*str_val, LOGMEM(NULL), LY_EMEM);
+ memcpy(*str_val, cbor_bytestring_handle(item), *str_len);
+ (*str_val)[*str_len] = '\0';
+ break;
+ case CBOR_TYPE_STRING:
+ *str_len = cbor_string_length(item);
+ *str_val = malloc(*str_len + 1);
+ LY_CHECK_ERR_RET(!*str_val, LOGMEM(NULL), LY_EMEM);
+ memcpy(*str_val, cbor_string_handle(item), *str_len);
+ (*str_val)[*str_len] = '\0';
+ break;
+ case CBOR_TYPE_FLOAT_CTRL:
+ if (cbor_float_ctrl_is_ctrl(item)) {
+ switch (cbor_ctrl_value(item)) {
+ case CBOR_CTRL_TRUE:
+ *str_val = strdup("true");
+ *str_len = 4;
+ break;
+ case CBOR_CTRL_FALSE:
+ *str_val = strdup("false");
+ *str_len = 5;
+ break;
+ case CBOR_CTRL_NULL:
+ *str_val = strdup("");
+ *str_len = 0;
+ break;
+ default:
+ LOGVAL(NULL, NULL, LYVE_SYNTAX, "Unsupported CBOR control value");
+ ret = LY_EVALID;
+ break;
+ }
+ LY_CHECK_ERR_RET(!*str_val, LOGMEM(NULL), LY_EMEM);
+ } else {
+ double val = cbor_float_get_float(item);
+ int len = snprintf(NULL, 0, "%g", val);
+
+ if (len < 0) {
+ return LY_ESYS;
+ }
+ *str_val = malloc(len + 1);
+ LY_CHECK_ERR_RET(!*str_val, LOGMEM(NULL), LY_EMEM);
+ sprintf(*str_val, "%g", val);
+ *str_len = len;
+ }
+ break;
+ default:
+ LOGVAL(NULL, NULL, LYVE_SYNTAX, "Unsupported CBOR data type %d", cbor_typeof(item));
+ ret = LY_EVALID;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Check in advance if the input data are parsable according to the provided @p snode.
+ *
+ * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
+ * is naturally done when the data are really parsed.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] snode Schema node corresponding to the member currently being processed.
+ * @param[in] cbor_value CBOR value to check.
+ * @param[out] type_hint_p Pointer to store detected value type hint.
+ * @return LY_SUCCESS if data are parsable.
+ * @return LY_ENOT if input data are not sufficient.
+ * @return LY_EINVAL in case of invalid encoding.
+ */
+static LY_ERR
+lydcbor_data_check_opaq(struct lyd_cbor_ctx *lydctx, const struct lysc_node *snode, const cbor_item_t *cbor_value,
+ uint32_t *type_hint_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ uint32_t *prev_lo, temp_lo = 0;
+ char *str_val = NULL;
+ size_t str_len = 0;
+
+ assert(snode);
+
+ if (!(snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
+ return LY_SUCCESS;
+ }
+
+ if (lydctx->parse_opts & LYD_PARSE_OPAQ) {
+ switch (snode->nodetype) {
+ case LYS_LEAFLIST:
+ case LYS_LEAF:
+ if ((ret = lydcbor_value_type_hint(lydctx, cbor_value, type_hint_p))) {
+ break;
+ }
+
+ prev_lo = ly_temp_log_options(&temp_lo);
+ ret = lydcbor_item_to_string(cbor_value, &str_val, &str_len);
+ if (ret == LY_SUCCESS) {
+ if (ly_value_validate(NULL, snode, str_val, str_len * 8, LY_VALUE_CBOR, NULL, *type_hint_p)) {
+ ret = LY_ENOT;
+ }
+ }
+ ly_temp_log_options(prev_lo);
+ free(str_val);
+ break;
+ case LYS_LIST:
+ /* Lists may not have all keys - handled elsewhere */
+ break;
+ }
+ } else if (snode->nodetype & LYD_NODE_TERM) {
+ ret = lydcbor_value_type_hint(lydctx, cbor_value, type_hint_p);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Join the forward-referencing metadata with their target data nodes.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in,out] first_p Pointer to the first sibling node.
+ * @return LY_SUCCESS on success.
+ * @return LY_EVALID if there are unresolved metadata.
+ */
+static LY_ERR
+lydcbor_metadata_finish(struct lyd_cbor_ctx *lydctx, struct lyd_node **first_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_node *node, *attr, *next, *meta_iter;
+ struct lysc_ext_instance *ext;
+ uint64_t instance = 0;
+ const char *prev = NULL;
+
+ /* finish linking metadata */
+ LY_LIST_FOR_SAFE(*first_p, next, attr)
+ {
+ struct lyd_node_opaq *meta_container = (struct lyd_node_opaq *)attr;
+ uint64_t match = 0;
+ ly_bool is_attr;
+ const char *name, *prefix;
+ size_t name_len, prefix_len;
+ const struct lysc_node *snode;
+
+ if (attr->schema || (meta_container->name.name[0] != '@')) {
+ continue;
+ }
+
+ if (prev != meta_container->name.name) {
+ lydict_remove(lydctx->cborctx->ctx, prev);
+ LY_CHECK_GOTO(ret = lydict_insert(lydctx->cborctx->ctx, meta_container->name.name, 0, &prev), cleanup);
+ instance = 1;
+ } else {
+ instance++;
+ }
+
+ /* find the corresponding data node */
+ LY_LIST_FOR(*first_p, node)
+ {
+ if (!node->schema) {
+ /* opaq node */
+ if (strcmp(&meta_container->name.name[1], ((struct lyd_node_opaq *)node)->name.name)) {
+ continue;
+ }
+
+ if (((struct lyd_node_opaq *)node)->hints & LYD_NODEHINT_LIST) {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_SYNTAX, "Metadata container references a sibling list node %s.",
+ ((struct lyd_node_opaq *)node)->name.name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ match++;
+ if (match != instance) {
+ continue;
+ }
+
+ LY_LIST_FOR(meta_container->child, meta_iter)
+ {
+ struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
+
+ ret = lyd_create_attr(node, NULL, lydctx->cborctx->ctx, meta->name.name, strlen(meta->name.name),
+ meta->name.prefix, ly_strlen(meta->name.prefix), meta->name.module_name,
+ ly_strlen(meta->name.module_name), meta->value, ly_strlen(meta->value), NULL, LY_VALUE_CBOR,
+ NULL, meta->hints);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ break;
+ } else {
+ lydcbor_parse_name(meta_container->name.name, strlen(meta_container->name.name), &name, &name_len,
+ &prefix, &prefix_len, &is_attr);
+ assert(is_attr);
+ lydcbor_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, lyd_parent(*first_p), &snode, &ext);
+
+ if (snode != node->schema) {
+ continue;
+ }
+
+ match++;
+ if (match != instance) {
+ continue;
+ }
+
+ LY_LIST_FOR(meta_container->child, meta_iter)
+ {
+ struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
+ struct lys_module *mod = NULL;
+
+ mod = ly_ctx_get_module_implemented(lydctx->cborctx->ctx, meta->name.prefix);
+ if (mod) {
+ ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
+ meta->name.name, strlen(meta->name.name), meta->value, ly_strlen(meta->value) * 8,
+ NULL, LY_VALUE_CBOR, NULL, meta->hints, node->schema, node);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else if (lydctx->parse_opts & LYD_PARSE_STRICT) {
+ if (meta->name.prefix) {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_REFERENCE,
+ "Unknown (or not implemented) YANG module \"%s\" of metadata \"%s%s%s\".",
+ meta->name.prefix, meta->name.prefix, ly_strlen(meta->name.prefix) ? ":" : "",
+ meta->name.name);
+ } else {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_REFERENCE, "Missing YANG module of metadata \"%s\".",
+ meta->name.name);
+ }
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+
+ ret = lyd_parser_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, ext);
+ LY_CHECK_GOTO(ret, cleanup);
+ break;
+ }
+ }
+
+ if (match != instance) {
+ if (instance > 1) {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_REFERENCE,
+ "Missing CBOR data instance #%" PRIu64 " to be coupled with %s metadata.",
+ instance, meta_container->name.name);
+ } else {
+ LOGVAL(lydctx->cborctx->ctx, NULL, LYVE_REFERENCE, "Missing CBOR data instance to be coupled with %s metadata.",
+ meta_container->name.name);
+ }
+ ret = LY_EVALID;
+ } else {
+ if (attr == (*first_p)) {
+ *first_p = attr->next;
+ }
+ lyd_free_tree(attr);
+ }
+ }
+
+cleanup:
+ lydict_remove(lydctx->cborctx->ctx, prev);
+ return ret;
+}
+
+/**
+ * @brief Parse a metadata member/attribute from CBOR.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] snode Schema node of the metadata parent.
+ * @param[in] node Parent node.
+ * @param[in] cbor_meta CBOR metadata item.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_meta_attr(struct lyd_cbor_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node,
+ const cbor_item_t *cbor_meta)
+{
+ LY_ERR rc = LY_SUCCESS, r;
+ enum cbor_type type;
+ const char *expected;
+ const char *name, *prefix = NULL;
+ size_t name_len, prefix_len = 0;
+ struct lys_module *mod;
+ const struct ly_ctx *ctx = lydctx->cborctx->ctx;
+ ly_bool is_attr = 0;
+ struct lyd_node *prev = node;
+ uint32_t instance = 0, val_hints;
+ uint16_t nodetype;
+ struct cbor_pair *pairs;
+ size_t map_size;
+
+ assert(snode || node);
+
+ nodetype = snode ? snode->nodetype : LYS_CONTAINER;
+ if (snode) {
+ LOG_LOCSET(snode);
+ }
+
+ type = cbor_typeof(cbor_meta);
+
+ /* check attribute encoding */
+ switch (nodetype) {
+ case LYS_LEAFLIST:
+ expected = "@name/array of objects/nulls";
+ LY_CHECK_GOTO(type != CBOR_TYPE_ARRAY, representation_error);
+
+ next_entry:
+ instance++;
+ if (!node || (node->schema != prev->schema)) {
+ LOGVAL(ctx, NULL, LYVE_REFERENCE, "Missing CBOR data instance #%" PRIu32 " of %s:%s to be coupled with metadata.",
+ instance, prev->schema->module->name, prev->schema->name);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* Process array item */
+ if (cbor_array_size(cbor_meta) > instance - 1) {
+ cbor_item_t **handle = cbor_array_handle(cbor_meta);
+ const cbor_item_t *item = handle[instance - 1];
+
+ if (lydcbor_is_null(item)) {
+ prev = node;
+ node = node->next;
+ if (instance < cbor_array_size(cbor_meta)) {
+ goto next_entry;
+ }
+ goto cleanup;
+ }
+ } else {
+ goto cleanup;
+ }
+ break;
+ case LYS_LEAF:
+ case LYS_ANYXML:
+ expected = "@name/object";
+ LY_CHECK_GOTO(type != CBOR_TYPE_MAP, representation_error);
+ break;
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_ANYDATA:
+ case LYS_NOTIF:
+ case LYS_ACTION:
+ case LYS_RPC:
+ expected = "@/object";
+ LY_CHECK_GOTO(type != CBOR_TYPE_MAP, representation_error);
+ break;
+ default:
+ LOGINT(ctx);
+ rc = LY_EINT;
+ goto cleanup;
+ }
+
+ /* process all members inside metadata object */
+ assert(type == CBOR_TYPE_MAP);
+ map_size = cbor_map_size(cbor_meta);
+ pairs = cbor_map_handle(cbor_meta);
+
+ for (size_t i = 0; i < map_size; ++i) {
+ const cbor_item_t *key_item = pairs[i].key;
+ const cbor_item_t *value_item = pairs[i].value;
+ char *key_str = NULL;
+ size_t key_len = 0;
+
+ if (!cbor_isa_string(key_item)) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Metadata key must be a string.");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+ LY_CHECK_GOTO(rc = lydcbor_item_to_string(key_item, &key_str, &key_len), cleanup);
+
+ lydcbor_parse_name(key_str, key_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+
+ if (!name_len) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Metadata in CBOR found with an empty name.");
+ free(key_str);
+ rc = LY_EVALID;
+ goto cleanup;
+ } else if (!prefix_len) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Metadata in CBOR must be namespace-qualified, missing prefix for \"%.*s\".",
+ (int)key_len, key_str);
+ free(key_str);
+ rc = LY_EVALID;
+ goto cleanup;
+ } else if (is_attr) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Invalid format of Metadata identifier in CBOR, unexpected '@' in \"%.*s\"",
+ (int)key_len, key_str);
+ free(key_str);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* get the element module */
+ mod = ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
+ if (!mod) {
+ if (lydctx->parse_opts & LYD_PARSE_STRICT) {
+ LOGVAL(ctx, NULL, LYVE_REFERENCE, "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
+ (int)prefix_len, prefix, (int)name_len, name);
+ free(key_str);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ if (node->schema) {
+ free(key_str);
+ continue;
+ }
+ assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
+ }
+
+ /* get value hints */
+ LY_CHECK_ERR_GOTO(rc = lydcbor_value_type_hint(lydctx, value_item, &val_hints), free(key_str), cleanup);
+
+ if (node->schema) {
+ char *str_val = NULL;
+ size_t str_len = 0;
+
+ LY_CHECK_ERR_GOTO(rc = lydcbor_item_to_string(value_item, &str_val, &str_len), free(key_str), cleanup);
+
+ /* create metadata */
+ rc = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod, name, name_len, str_val,
+ str_len * 8, NULL, LY_VALUE_CBOR, NULL, val_hints, node->schema, node);
+ free(str_val);
+ LY_CHECK_ERR_GOTO(rc, free(key_str), cleanup);
+
+ /* add/correct flags */
+ rc = lyd_parser_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, NULL);
+ LY_CHECK_ERR_GOTO(rc, free(key_str), cleanup);
+ } else {
+ /* create attribute */
+ const char *module_name;
+ size_t module_name_len;
+ char *str_val = NULL;
+ size_t str_len = 0;
+
+ lydcbor_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
+
+ LY_CHECK_ERR_GOTO(rc = lydcbor_item_to_string(value_item, &str_val, &str_len), free(key_str), cleanup);
+
+ rc = lyd_create_attr(node, NULL, ctx, name, name_len, prefix, prefix_len, module_name,
+ module_name_len, str_val, str_len, NULL, LY_VALUE_CBOR, NULL, val_hints);
+ free(str_val);
+ LY_CHECK_ERR_GOTO(rc, free(key_str), cleanup);
+ }
+
+ free(key_str);
+ }
+
+ if ((nodetype == LYS_LEAFLIST) && (instance < cbor_array_size(cbor_meta))) {
+ prev = node;
+ node = node->next;
+ goto next_entry;
+ }
+
+ goto cleanup;
+
+representation_error:
+ LOGVAL(ctx, NULL, LYVE_SYNTAX,
+ "The attribute(s) of %s \"%s\" is expected to be represented as CBOR %s, but input data contains different type.",
+ lys_nodetype2str(nodetype), node ? LYD_NAME(node) : LYD_NAME(prev), expected);
+ rc = LY_EVALID;
+
+cleanup:
+ if ((rc == LY_EVALID) && (lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR)) {
+ if ((r = lydcbor_data_skip(lydctx->cborctx))) {
+ rc = r;
+ }
+ }
+ LOG_LOCBACK(snode ? 1 : 0);
+ return rc;
+}
+
+/**
+ * @brief Create an opaq node from CBOR.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] name Name of the opaq node.
+ * @param[in] name_len Length of @p name.
+ * @param[in] prefix Prefix of the opaq node.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] parent Data parent.
+ * @param[in] cbor_value CBOR value item.
+ * @param[out] node_p Pointer to the created opaq node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_create_opaq(struct lyd_cbor_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
+ struct lyd_node *parent, const cbor_item_t *cbor_value, struct lyd_node **node_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ const char *value = NULL, *module_name;
+ size_t value_len = 0, module_name_len = 0;
+ ly_bool dynamic = 0;
+ uint32_t type_hint = 0;
+ char *str_val = NULL;
+
+ if (cbor_typeof(cbor_value) != CBOR_TYPE_MAP) {
+ /* prepare for creating opaq node with a value */
+ LY_CHECK_RET(lydcbor_item_to_string(cbor_value, &str_val, &value_len));
+ value = str_val;
+ dynamic = 1;
+
+ LY_CHECK_GOTO(ret = lydcbor_value_type_hint(lydctx, cbor_value, &type_hint), cleanup);
+ }
+
+ /* get the module name */
+ lydcbor_get_node_prefix(parent, prefix, prefix_len, &module_name, &module_name_len);
+ if (!module_name && !parent && lydctx->any_schema) {
+ module_name = lydctx->any_schema->module->name;
+ module_name_len = strlen(module_name);
+ }
+
+ /* create node */
+ ret = lyd_create_opaq(lydctx->cborctx->ctx, name, name_len, prefix, prefix_len, module_name, module_name_len, value,
+ value_len, &dynamic, LY_VALUE_CBOR, NULL, type_hint, node_p);
+
+cleanup:
+ if (dynamic) {
+ free((char *)value);
+ }
+ return ret;
+}
+
+static LY_ERR lydcbor_subtree_r(struct lyd_cbor_ctx *lydctx, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_set *parsed, const cbor_item_t *cbor_obj);
+
+/**
+ * @brief Parse opaq node from CBOR.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] name Name of the opaq node.
+ * @param[in] name_len Length of @p name.
+ * @param[in] prefix Prefix of the opaq node.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] parent Data parent.
+ * @param[in] cbor_value CBOR value item.
+ * @param[in,out] first_p First top-level/parent sibling.
+ * @param[out] node_p Pointer to the created opaq node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_parse_opaq(struct lyd_cbor_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
+ struct lyd_node *parent, const cbor_item_t *cbor_value, struct lyd_node **first_p, struct lyd_node **node_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ enum cbor_type type = cbor_typeof(cbor_value);
+
+ LY_CHECK_GOTO(ret = lydcbor_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, cbor_value, node_p), cleanup);
+
+ if ((type == CBOR_TYPE_ARRAY) && (cbor_array_size(cbor_value) == 1)) {
+ cbor_item_t **handle = cbor_array_handle(cbor_value);
+
+ if (lydcbor_is_null(handle[0])) {
+ /* special array null value */
+ ((struct lyd_node_opaq *)*node_p)->hints |= LYD_VALHINT_EMPTY;
+ goto finish;
+ }
+ }
+
+ if (type == CBOR_TYPE_ARRAY) {
+ /* process array */
+ size_t array_size = cbor_array_size(cbor_value);
+ cbor_item_t **array_handle = cbor_array_handle(cbor_value);
+
+ for (size_t i = 0; i < array_size; ++i) {
+ const cbor_item_t *item = array_handle[i];
+
+ if (cbor_typeof(item) == CBOR_TYPE_MAP) {
+ /* array with objects, list */
+ ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST;
+
+ /* process children */
+ LY_CHECK_GOTO(ret = lydcbor_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL, item), cleanup);
+ } else {
+ /* array with values, leaf-list */
+ ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LEAFLIST;
+ }
+
+ if (i < array_size - 1) {
+ /* continue with next instance */
+ assert(*node_p);
+ LY_CHECK_GOTO(ret = lyd_parser_node_insert(parent, first_p, NULL, lydctx->parse_opts, *node_p), cleanup);
+ *node_p = NULL;
+
+ LY_CHECK_GOTO(ret = lydcbor_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, item, node_p), cleanup);
+ }
+ }
+ } else if (type == CBOR_TYPE_MAP) {
+ ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_CONTAINER;
+ /* process children */
+ LY_CHECK_GOTO(ret = lydcbor_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL, cbor_value), cleanup);
+ }
+
+finish:
+ /* finish linking metadata */
+ ret = lydcbor_metadata_finish(lydctx, lyd_node_child_p(*node_p));
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Process the attribute container (starting by @).
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] attr_node The data node referenced by the attribute container.
+ * @param[in] snode The schema node of the data node.
+ * @param[in] name Name of the node.
+ * @param[in] name_len Length of @p name.
+ * @param[in] prefix Prefix of the node.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] parent Data parent.
+ * @param[in] cbor_value CBOR value item.
+ * @param[in,out] first_p First top-level/parent sibling.
+ * @param[out] node_p Pointer to the created node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_parse_attribute(struct lyd_cbor_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
+ const char *name, size_t name_len, const char *prefix, size_t prefix_len, struct lyd_node *parent,
+ const cbor_item_t *cbor_value, struct lyd_node **first_p, struct lyd_node **node_p)
+{
+ LY_ERR r;
+ const char *opaq_name, *mod_name, *attr_mod = NULL;
+ size_t opaq_name_len, attr_mod_len = 0;
+
+ if (!attr_node) {
+ /* learn the attribute module name */
+ if (!snode) {
+ if (!prefix) {
+ lydcbor_get_node_prefix(parent, NULL, 0, &attr_mod, &attr_mod_len);
+ } else {
+ attr_mod = prefix;
+ attr_mod_len = prefix_len;
+ }
+ }
+
+ /* try to find the instance */
+ LY_LIST_FOR(parent ? lyd_child(parent) : *first_p, attr_node)
+ {
+ if (snode) {
+ if (attr_node->schema) {
+ if (attr_node->schema == snode) {
+ break;
+ }
+ } else {
+ mod_name = ((struct lyd_node_opaq *)attr_node)->name.module_name;
+ if (!strcmp(LYD_NAME(attr_node), snode->name) && mod_name && !strcmp(mod_name, snode->module->name)) {
+ break;
+ }
+ }
+ } else {
+ if (attr_node->schema) {
+ mod_name = attr_node->schema->module->name;
+ } else {
+ mod_name = ((struct lyd_node_opaq *)attr_node)->name.module_name;
+ }
+
+ if (!ly_strncmp(LYD_NAME(attr_node), name, name_len) && mod_name && attr_mod &&
+ !ly_strncmp(mod_name, attr_mod, attr_mod_len)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (!attr_node) {
+ /* parse as an opaq node with @ prefix */
+ uint32_t prev_opts;
+
+ prev_opts = lydctx->parse_opts;
+ lydctx->parse_opts &= ~LYD_PARSE_STRICT;
+ lydctx->parse_opts |= LYD_PARSE_OPAQ;
+
+ opaq_name = prefix ? prefix - 1 : name - 1;
+ opaq_name_len = prefix ? prefix_len + name_len + 2 : name_len + 1;
+ r = lydcbor_parse_opaq(lydctx, opaq_name, opaq_name_len, NULL, 0, parent, cbor_value, first_p, node_p);
+
+ lydctx->parse_opts = prev_opts;
+ LY_CHECK_RET(r);
+ } else {
+ LY_CHECK_RET(lydcbor_meta_attr(lydctx, snode, attr_node, cbor_value));
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse a single anydata/anyxml node from CBOR.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] snode Schema node corresponding to the member.
+ * @param[in] ext Extension instance of @p snode, if any.
+ * @param[in] cbor_value CBOR value item.
+ * @param[out] node Parsed data (or opaque) node.
+ * @return LY_SUCCESS if a node was successfully parsed.
+ * @return LY_ENOT in case of invalid CBOR encoding.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+lydcbor_parse_any(struct lyd_cbor_ctx *lydctx, const struct lysc_node *snode, struct lysc_ext_instance *ext,
+ const cbor_item_t *cbor_value, struct lyd_node **node)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ uint32_t prev_parse_opts = lydctx->parse_opts, prev_int_opts = lydctx->int_opts;
+ struct lyd_node *child = NULL;
+ enum cbor_type type = cbor_typeof(cbor_value);
+
+ assert(snode->nodetype & LYD_NODE_ANY);
+
+ *node = NULL;
+
+ /* status check according to allowed CBOR types */
+ if (snode->nodetype == LYS_ANYXML) {
+ LY_CHECK_RET((type != CBOR_TYPE_MAP) && (type != CBOR_TYPE_ARRAY) && (type != CBOR_TYPE_UINT) &&
+ (type != CBOR_TYPE_NEGINT) && (type != CBOR_TYPE_STRING) && (type != CBOR_TYPE_FLOAT_CTRL),
+ LY_ENOT);
+ } else {
+ LY_CHECK_RET(type != CBOR_TYPE_MAP, LY_ENOT);
+ }
+
+ /* create any node */
+ if (type == CBOR_TYPE_MAP) {
+ /* create node */
+ r = lyd_create_any(snode, NULL, NULL, 0, 1, 0, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ /* parse data tree with correct options */
+ lydctx->parse_opts &= ~LYD_PARSE_STRICT;
+ lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
+ lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
+ lydctx->any_schema = snode;
+
+ /* process the anydata content */
+ r = lydcbor_subtree_r(lydctx, *node, &child, NULL, cbor_value);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ /* finish linking metadata */
+ r = lydcbor_metadata_finish(lydctx, &child);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ /* assign the data tree */
+ ((struct lyd_node_any *)*node)->child = child;
+ child = NULL;
+ } else {
+ /* convert CBOR scalar value to string and store */
+ char *str_val = NULL;
+ size_t str_len = 0;
+
+ r = lydcbor_item_to_string(cbor_value, &str_val, &str_len);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ r = lyd_create_any(snode, NULL, str_val, LYD_VALHINT_STRING, 1, 0, node);
+ LY_CHECK_ERR_GOTO(r, free(str_val); rc = r, cleanup);
+ }
+
+cleanup:
+ lydctx->parse_opts = prev_parse_opts;
+ lydctx->int_opts = prev_int_opts;
+ lydctx->any_schema = NULL;
+ lyd_free_tree(child);
+ return rc;
+}
+
+/**
+ * @brief Parse a single instance of an inner node from CBOR.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] snode Schema node corresponding to the member.
+ * @param[in] ext Extension instance of @p snode, if any.
+ * @param[in] cbor_value CBOR value item.
+ * @param[out] node Parsed data (or opaque) node.
+ * @return LY_SUCCESS if a node was successfully parsed.
+ * @return LY_ENOT in case of invalid CBOR encoding.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+lydcbor_parse_instance_inner(struct lyd_cbor_ctx *lydctx, const struct lysc_node *snode, struct lysc_ext_instance *ext,
+ const cbor_item_t *cbor_value, struct lyd_node **node)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ uint32_t prev_parse_opts = lydctx->parse_opts;
+
+ LY_CHECK_RET(cbor_typeof(cbor_value) != CBOR_TYPE_MAP, LY_ENOT);
+
+ /* create inner node */
+ LY_CHECK_RET(lyd_create_inner(snode, node));
+
+ /* use it for logging */
+ /* dnode-only location no longer supported by LOG_LOCSET */
+
+ if (ext) {
+ /* only parse these extension data and validate afterwards */
+ lydctx->parse_opts |= LYD_PARSE_ONLY;
+ }
+
+ /* process children */
+ r = lydcbor_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL, cbor_value);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ /* finish linking metadata */
+ r = lydcbor_metadata_finish(lydctx, lyd_node_child_p(*node));
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ if (snode->nodetype == LYS_LIST) {
+ /* check all keys exist */
+ r = lyd_parser_check_keys(*node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY) && !rc) {
+ /* new node validation */
+ r = lyd_parser_validate_new_implicit((struct lyd_ctx *)lydctx, *node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+cleanup:
+ lydctx->parse_opts = prev_parse_opts;
+ if (!(*node)->hash) {
+ /* list without keys is unusable */
+ lyd_free_tree(*node);
+ *node = NULL;
+ }
+ return rc;
+}
+
+/**
+ * @brief Parse a single instance of a node from CBOR.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] parent Data parent of the subtree.
+ * @param[in,out] first_p Pointer to the variable holding the first top-level sibling.
+ * @param[in] snode Schema node corresponding to the member.
+ * @param[in] ext Extension instance of @p snode, if any.
+ * @param[in] name Parsed CBOR node name.
+ * @param[in] name_len Length of @p name.
+ * @param[in] prefix Parsed CBOR node prefix.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] cbor_value CBOR value item.
+ * @param[out] node Parsed data (or opaque) node.
+ * @return LY_SUCCESS if a node was successfully parsed.
+ * @return LY_ENOT in case of invalid CBOR encoding.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+lydcbor_parse_instance(struct lyd_cbor_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
+ const struct lysc_node *snode, struct lysc_ext_instance *ext, const char *name, size_t name_len,
+ const char *prefix, size_t prefix_len, const cbor_item_t *cbor_value, struct lyd_node **node)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ uint32_t type_hints = 0;
+ char *str_val = NULL;
+ size_t str_len = 0;
+
+ LOG_LOCSET(snode);
+
+ r = lydcbor_data_check_opaq(lydctx, snode, cbor_value, &type_hints);
+ if (r == LY_SUCCESS) {
+ assert(snode->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER | LYD_NODE_ANY));
+ if (lydcbor_is_null(cbor_value)) {
+ /* do not do anything if value is CBOR null */
+ goto cleanup;
+ } else if (snode->nodetype & LYD_NODE_TERM) {
+ enum cbor_type type = cbor_typeof(cbor_value);
+
+ if ((type == CBOR_TYPE_ARRAY) && (cbor_array_size(cbor_value) == 1)) {
+ cbor_item_t **handle = cbor_array_handle(cbor_value);
+
+ if (lydcbor_is_null(handle[0])) {
+ /* [null] case */
+ str_val = strdup("");
+ str_len = 0;
+ }
+ }
+ if (!str_val) {
+ if ((type != CBOR_TYPE_ARRAY) && (type != CBOR_TYPE_UINT) && (type != CBOR_TYPE_NEGINT) &&
+ (type != CBOR_TYPE_STRING) && (type != CBOR_TYPE_FLOAT_CTRL)) {
+ rc = LY_ENOT;
+ goto cleanup;
+ }
+
+ /* create terminal node */
+ r = lydcbor_item_to_string(cbor_value, &str_val, &str_len);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ }
+
+ r = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, parent, str_val, str_len * 8,
+ NULL, LY_VALUE_CBOR, NULL, type_hints, node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ } else if (snode->nodetype & LYD_NODE_INNER) {
+ /* create inner node */
+ r = lydcbor_parse_instance_inner(lydctx, snode, ext, cbor_value, node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ } else {
+ /* create any node */
+ r = lydcbor_parse_any(lydctx, snode, ext, cbor_value, node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+ LY_CHECK_GOTO(!*node, cleanup);
+
+ /* add/correct flags */
+ r = lyd_parser_set_data_flags(*node, &(*node)->meta, (struct lyd_ctx *)lydctx, ext);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
+ /* store for ext instance node validation, if needed */
+ r = lyd_validate_node_ext(*node, &lydctx->ext_node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ }
+ } else if (r == LY_ENOT) {
+ /* parse it again as an opaq node */
+ r = lydcbor_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, cbor_value, first_p, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ if (snode->nodetype == LYS_LIST) {
+ ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LIST;
+ } else if (snode->nodetype == LYS_LEAFLIST) {
+ ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LEAFLIST;
+ }
+ } else {
+ /* error */
+ rc = r;
+ goto cleanup;
+ }
+
+cleanup:
+ free(str_val);
+ LOG_LOCBACK(1);
+ return rc;
+}
+
+/**
+ * @brief Parse CBOR subtree. All leaf-list and list instances of a node are considered one subtree.
+ *
+ * @param[in] lydctx CBOR data parser context.
+ * @param[in] parent Data parent of the subtree, must be set if @p first_p is not.
+ * @param[in,out] first_p Pointer to the variable holding the first top-level sibling.
+ * @param[in,out] parsed Optional set to add all the parsed siblings into.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydcbor_subtree_r(struct lyd_cbor_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
+ struct ly_set *parsed, const cbor_item_t *cbor_obj)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ const char *name, *prefix = NULL, *expected = NULL;
+ size_t name_len, prefix_len = 0;
+ ly_bool is_meta = 0;
+ const struct lysc_node *snode = NULL;
+ struct lysc_ext_instance *ext = NULL;
+ struct lyd_node *node = NULL, *attr_node = NULL;
+ const struct ly_ctx *ctx = lydctx->cborctx->ctx;
+ struct cbor_pair *pairs;
+ size_t map_size;
+
+ assert(parent || first_p);
+ assert(cbor_typeof(cbor_obj) == CBOR_TYPE_MAP);
+
+ map_size = cbor_map_size(cbor_obj);
+ pairs = cbor_map_handle(cbor_obj);
+
+ if (!pairs && (map_size > 0)) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Invalid CBOR map structure");
+ return LY_EVALID;
+ }
+
+ /* process all members */
+ for (size_t i = 0; i < map_size; ++i) {
+ const cbor_item_t *key_item = pairs[i].key;
+ const cbor_item_t *value_item = pairs[i].value;
+ char *key_str = NULL;
+ size_t key_len = 0;
+
+ if (!key_item || !value_item) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Null key or value in CBOR map");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* Skip null values */
+ if (lydcbor_is_null(value_item)) {
+ continue;
+ }
+
+ /* Get key string */
+ if (!cbor_isa_string(key_item)) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "CBOR map key must be string for named identifier format");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+ LY_CHECK_ERR_GOTO(rc = lydcbor_item_to_string(key_item, &key_str, &key_len), free(key_str), cleanup);
+
+ /* process the node name */
+ lydcbor_parse_name(key_str, key_len, &name, &name_len, &prefix, &prefix_len, &is_meta);
+
+ if (!is_meta || name_len || prefix_len) {
+ /* get the schema node */
+ r = lydcbor_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, parent, &snode, &ext);
+ if (r == LY_ENOT) {
+ free(key_str);
+ continue;
+ } else if ((r == LY_EVALID) && (lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR)) {
+ rc = r;
+ free(key_str);
+ continue;
+ } else if (r) {
+ rc = r;
+ free(key_str);
+ goto cleanup;
+ }
+ }
+
+ if (is_meta) {
+ /* parse as metadata */
+ if (!name_len && !prefix_len && !parent) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX,
+ "Invalid metadata format - \"@\" can be used only inside anydata, container or list entries.");
+ r = LY_EVALID;
+ free(key_str);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ } else if (!name_len && !prefix_len) {
+ /* parent's metadata without a name */
+ attr_node = parent;
+ snode = attr_node->schema;
+ }
+ r = lydcbor_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent,
+ value_item, first_p, &node);
+ free(key_str);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ } else if (!snode) {
+ if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
+ /* skip element */
+ free(key_str);
+ continue;
+ } else {
+ /* parse as an opaq node */
+ if (name_len == 0) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "CBOR object member name cannot be a zero-length string.");
+ r = LY_EVALID;
+ free(key_str);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ /* parse opaq */
+ r = lydcbor_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, value_item, first_p, &node);
+ free(key_str);
+ key_str = NULL;
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ }
+ } else {
+ /* parse as a standard lyd_node but it can still turn out to be an opaque node */
+
+ /* set expected representation */
+ switch (snode->nodetype) {
+ case LYS_LEAFLIST:
+ expected = "name/array of values";
+ break;
+ case LYS_LIST:
+ expected = "name/array of objects";
+ break;
+ case LYS_LEAF:
+ expected = "name/value";
+ break;
+ case LYS_CONTAINER:
+ case LYS_NOTIF:
+ case LYS_ACTION:
+ case LYS_RPC:
+ case LYS_ANYDATA:
+ expected = "name/object";
+ break;
+ case LYS_ANYXML:
+ expected = "name/value";
+ break;
+ }
+
+ /* check the representation and process */
+ enum cbor_type value_type = cbor_typeof(value_item);
+
+ switch (snode->nodetype) {
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ if (value_type != CBOR_TYPE_ARRAY) {
+ goto representation_error;
+ }
+
+ /* process all values/objects in array */
+ size_t array_size = cbor_array_size(value_item);
+ cbor_item_t **array_handle = cbor_array_handle(value_item);
+
+ for (size_t j = 0; j < array_size; ++j) {
+ const cbor_item_t *item = array_handle[j];
+
+ r = lydcbor_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
+ item, &node);
+ if (r == LY_ENOT) {
+ free(key_str);
+ goto representation_error;
+ }
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ r = lyd_parser_node_insert(parent, first_p, NULL, lydctx->parse_opts, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ node = NULL;
+ }
+ break;
+ case LYS_LEAF:
+ case LYS_CONTAINER:
+ case LYS_NOTIF:
+ case LYS_ACTION:
+ case LYS_RPC:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ /* process the value/object */
+ r = lydcbor_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
+ value_item, &node);
+ if (r == LY_ENOT) {
+ free(key_str);
+ goto representation_error;
+ }
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ /* remember the RPC/action/notification */
+ lydctx->op_node = node;
+ }
+ break;
+ }
+ }
+
+ free(key_str);
+
+ /* remember a successfully parsed node */
+ if (parsed && node) {
+ ly_set_add(parsed, node, 1, NULL);
+ }
+
+ /* finally connect the parsed node */
+ r = lyd_parser_node_insert(parent, first_p, NULL, lydctx->parse_opts, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ node = NULL;
+ }
+
+ /* success */
+ goto cleanup;
+
+representation_error:
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Expecting CBOR %s but %s \"%s\" is represented in input data differently.",
+ expected, lys_nodetype2str(snode->nodetype), snode->name);
+ rc = LY_EVALID;
+ if (lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) {
+ /* try to skip the invalid data */
+ if ((r = lydcbor_data_skip(lydctx->cborctx))) {
+ rc = r;
+ }
+ }
+
+cleanup:
+ lyd_free_tree(node);
+ return rc;
+}
+
+/**
+ * @brief Common start of CBOR parser processing different types of input data.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] in Input structure.
+ * @param[in] parse_opts Options for parser.
+ * @param[in] val_opts Options for validation phase.
+ * @param[out] lydctx_p Data parser context to finish validation.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_parse_cbor_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
+ struct lyd_cbor_ctx **lydctx_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_cbor_ctx *lydctx;
+ enum cbor_type cbortype;
+
+ assert(lydctx_p);
+
+ /* init context */
+ lydctx = calloc(1, sizeof *lydctx);
+ LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
+ lydctx->parse_opts = parse_opts;
+ lydctx->val_opts = val_opts;
+ lydctx->free = lyd_cbor_ctx_free;
+
+ /* Create low-level CBOR context */
+ LY_CHECK_ERR_RET(ret = lycbor_ctx_new(ctx, in, &lydctx->cborctx), free(lydctx), ret);
+ cbortype = cbor_typeof(lydctx->cborctx->cbor_data);
+
+ if (!cbor_isa_map(lydctx->cborctx->cbor_data)) {
+ /* expecting top-level map */
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Expected top-level CBOR map, but %d found.", cbortype);
+ *lydctx_p = NULL;
+ lyd_cbor_ctx_free((struct lyd_ctx *)lydctx);
+ return LY_EVALID;
+ }
+
+ *lydctx_p = lydctx;
+ return ret;
+}
+
+LY_ERR
+lyd_parse_cbor(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ struct lyd_cbor_ctx *lydctx = NULL;
+
+ rc = lyd_parse_cbor_init(ctx, in, parse_opts, val_opts, &lydctx);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ lydctx->int_opts = int_opts;
+ lydctx->ext = ext;
+
+ /* find the operation node if it exists already */
+ LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
+
+ /* read subtree(s) */
+ r = lydcbor_subtree_r(lydctx, parent, first_p, parsed, lydctx->cborctx->cbor_data);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && *first_p && (*first_p)->next) {
+ LOGVAL(ctx, NULL, LYVE_SYNTAX, "Unexpected sibling node.");
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+ if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
+ LOGVAL(ctx, NULL, LYVE_DATA, "Missing the operation node.");
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ /* finish linking metadata */
+ r = lydcbor_metadata_finish(lydctx, parent ? lyd_node_child_p(parent) : first_p);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ /* parse_opts & LYD_PARSE_SUBTREE not implemented */
+ (void)subtree_sibling;
+
+cleanup:
+ /* there should be no unresolved types stored */
+ assert(!(parse_opts & LYD_PARSE_ONLY) || !lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
+
+ if (rc && (!lydctx || !(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) || (rc != LY_EVALID))) {
+ lyd_cbor_ctx_free((struct lyd_ctx *)lydctx);
+ lydctx = NULL;
+ } else {
+ *lydctx_p = (struct lyd_ctx *)lydctx;
+ lycbor_ctx_free(lydctx->cborctx);
+ lydctx->cborctx = NULL;
+ }
+ return rc;
+}
diff --git a/src/parser_data.h b/src/parser_data.h
index 3941354c5f..a7c2262450 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -41,6 +41,11 @@ struct ly_in;
* Notifications, so the representation of these data trees is proprietary and corresponds to the representation of these
* trees in XML.
*
+ * - CBOR
+ *
+ * The reference documentation would be `Encoding of Data Modeled with YANG in the Concise Binary Object
+ * Representation (CBOR)` : [RFC 9254](https://datatracker.ietf.org/doc/html/rfc9254).
+ *
* While the parsers themselves process the input data only syntactically, all the parser functions actually incorporate
* the [common validator](@ref howtoDataValidation) checking the input data semantically. Therefore, the parser functions
* accepts two groups of options - @ref dataparseroptions and @ref datavalidationoptions.
@@ -224,6 +229,11 @@ struct ly_in;
/**
* @brief Parse (and validate) data from the input handler as a YANG data tree.
*
+ * When parsing subtrees (i.e., when @p parent is non-NULL), validation is only performed on the newly parsed data.
+ * This might result in allowing invalid datastore content when the schema contains cross-branch constraints,
+ * complicated `must` statements, etc. When a full-datastore validation is desirable, parse all subtrees
+ * first, and then request validation of the complete datastore content.
+ *
* @param[in] ctx Context to connect with the tree being built here.
* @param[in] parent Optional parent to connect the parsed nodes to. If provided, the data are expected to describe
* a subtree of the YANG module instead of starting at the schema root.
@@ -234,11 +244,6 @@ struct ly_in;
* @param[out] tree Full parsed data tree, note that NULL can be a valid tree. If @p parent is set, the first parsed child.
* @return LY_SUCCESS in case of successful parsing (and validation).
* @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
- *
- * When parsing subtrees (i.e., when @p parent is non-NULL), validation is only performed on the newly parsed data.
- * This might result in allowing invalid datastore content when the schema contains cross-branch constraints,
- * complicated `must` statements, etc. When a full-datastore validation is desirable, parse all subtrees
- * first, and then request validation of the complete datastore content.
*/
LIBYANG_API_DECL LY_ERR lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
@@ -260,6 +265,25 @@ LIBYANG_API_DECL LY_ERR lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node
LIBYANG_API_DECL LY_ERR lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, uint32_t parse_options,
uint32_t validate_options, struct lyd_node **tree);
+/**
+ * @brief Parse (and validate) input data as a YANG data tree from a bounded memory buffer.
+ *
+ * Wrapper around ::lyd_parse_data() hiding work with the input handler and some obscure options.
+ * Unlike ::lyd_parse_data_mem(), @p data may contain NULL bytes and the parser will not read past @p data_len bytes.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] data The input data in the specified @p format to parse (and validate).
+ * @param[in] data_len Number of readable bytes in @p data.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] parse_options Options for parser, see @ref dataparseroptions.
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ * @param[out] tree Full parsed data tree, note that NULL can be a valid tree.
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LIBYANG_API_DECL LY_ERR lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, uint32_t data_len, LYD_FORMAT format,
+ uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
+
/**
* @brief Parse (and validate) input data as a YANG data tree.
*
diff --git a/src/parser_internal.h b/src/parser_internal.h
index ece6f9fe5f..deab929f6e 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -22,6 +22,7 @@
struct lyd_ctx;
struct ly_in;
+struct lycbor_ctx;
struct lysp_ext_substmt;
struct lysp_stmt;
struct lysp_yang_ctx;
@@ -69,7 +70,7 @@ typedef void (*lyd_ctx_free_clb)(struct lyd_ctx *ctx);
/**
* @brief Internal (common) context for YANG data parsers.
*
- * Covers ::lyd_xml_ctx, ::lyd_json_ctx and ::lyd_lyb_ctx.
+ * Covers ::lyd_xml_ctx, ::lyd_json_ctx, ::lyd_lyb_ctx and ::lyd_cbor_ctx.
*/
struct lyd_ctx {
uint32_t parse_opts; /**< various @ref dataparseroptions. */
@@ -175,6 +176,32 @@ struct lyd_lyb_ctx {
};
};
+/**
+ * @brief Internal context for CBOR data parser.
+ */
+struct lyd_cbor_ctx {
+ uint32_t parse_opts; /**< various @ref dataparseroptions. */
+ uint32_t val_opts; /**< various @ref datavalidationoptions. */
+ uint32_t int_opts; /**< internal parser options */
+ uint32_t path_len; /**< used bytes in the path buffer */
+ char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
+ struct ly_set node_when; /**< set of nodes with "when" conditions */
+ struct ly_set node_types; /**< set of nodes with unresolved types */
+ struct ly_set meta_types; /**< set of metadata with unresolved types */
+ struct ly_set ext_val; /**< set of nested extension data to validate */
+ struct lyd_node *op_node; /**< if an operation is being parsed, its node */
+ const struct lys_module *val_getnext_ht_mod;
+ struct ly_ht *val_getnext_ht;
+
+ /* callbacks */
+ lyd_ctx_free_clb free; /**< destructor */
+
+ struct lycbor_ctx *cborctx; /**< CBOR context for low-level operations */
+ const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context, NULL if none */
+ struct ly_set ext_node; /**< set of nodes with extension instances to validate */
+ const struct lysc_node *any_schema; /**< parent anyxml/anydata schema node if parsing nested data tree */
+};
+
/**
* @brief Parsed extension instance data to validate.
*/
@@ -325,6 +352,29 @@ LY_ERR lyd_parse_json_restconf(const struct ly_ctx *ctx, struct lyd_node *parent
LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+/**
+ * @brief Parse CBOR data into libyang data tree.
+ *
+ * This function mirrors the signature and behavior of lyd_parse_json() but handles
+ * CBOR input instead. It supports both named identifier and SID formats.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] ext Optional extension instance to parse data following the schema tree specified in the extension instance
+ * @param[in] parent Parent to connect the parsed nodes to, if any.
+ * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
+ * @param[in] in Input structure to read from.
+ * @param[in] parse_opts Options for parser, see @ref dataparseroptions.
+ * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
+ * @param[in] int_opts Internal data parser options.
+ * @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
+ * @param[out] lydctx_p Data parser context to finish validation.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_cbor(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
+
/**
* @brief Validate eventTime date-and-time value.
*
diff --git a/src/parser_json.c b/src/parser_json.c
index 5f045bd510..fca21089b0 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -267,16 +267,26 @@ lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *pref
}
/* try to find parent schema node */
- if (parent && parent->schema && !(parent->schema->nodetype & LYD_NODE_ANY)) {
+ if (parent && parent->schema) {
/* use only a schema parent */
sparent = parent->schema;
} else {
sparent = NULL;
}
+ if (sparent && (sparent->nodetype & LYD_NODE_ANY)) {
+ if (!prefix_len) {
+ /* inherit the module */
+ mod = sparent->module;
+ }
+
+ /* do not search in children */
+ sparent = NULL;
+ }
+
if (!prefix_len) {
prefix = NULL;
}
- r = lys_find_child_node(parent ? LYD_CTX(parent) : lydctx->jsonctx->ctx, sparent, NULL, prefix, prefix_len,
+ r = lys_find_child_node(parent ? LYD_CTX(parent) : lydctx->jsonctx->ctx, sparent, mod, prefix, prefix_len,
LY_VALUE_JSON, NULL, name, name_len, getnext_opts, snode, ext);
LY_CHECK_RET(r && (r != LY_ENOT), r);
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index f80cc0f354..21e30a5a9f 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -44,7 +44,7 @@
#include "xml.h"
static LY_ERR lyb_parse_siblings(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, ly_bool is_root,
- struct lyd_node **first_p, struct ly_set *parsed);
+ struct lyd_node *pparent, struct lyd_node **first_p, struct ly_set *parsed);
/**
* @brief Free a LYB data parser context.
@@ -74,8 +74,9 @@ lyb_parse_ctx_free(struct lyd_ctx *lydctx)
* @param[in,out] buf Destination buffer, @p count_bits rightmost bits are written to, rest are shifted left.
* @param[in] count_bits Number of bits to read.
* @param[in] lybctx LYB context.
+ * @return LY_ERR value.
*/
-static void
+static LY_ERR
lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
{
uint8_t count_buf_bits = 0, count_bits_remainder, new_buf;
@@ -84,14 +85,14 @@ lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
assert(lybctx);
if (!count_bits) {
- return;
+ return LY_SUCCESS;
}
if (!lybctx->shrink) {
/* just read full bytes */
count_bytes = LYPLG_BITS2BYTES(count_bits);
- ly_in_read(lybctx->in, buf, count_bytes);
- return;
+ LY_CHECK_GOTO(ly_in_read(lybctx->in, buf, count_bytes), eof);
+ return LY_SUCCESS;
}
if (lybctx->buf_bits) {
@@ -106,7 +107,7 @@ lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
if (count_bytes) {
if (buf) {
/* read the bytes */
- ly_in_read(lybctx->in, buf, count_bytes);
+ LY_CHECK_GOTO(ly_in_read(lybctx->in, buf, count_bytes), eof);
if (count_bits_remainder) {
/* prepare new buffered bits */
new_buf = ((uint8_t *)buf)[count_bytes - 1];
@@ -117,11 +118,11 @@ lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
} else {
if (count_bits_remainder) {
/* skip the bytes and prepare the new buffered bits */
- ly_in_skip(lybctx->in, count_bytes - 1);
- ly_in_read(lybctx->in, &new_buf, 1);
+ LY_CHECK_GOTO(ly_in_skip(lybctx->in, count_bytes - 1), eof);
+ LY_CHECK_GOTO(ly_in_read(lybctx->in, &new_buf, 1), eof);
} else {
/* just skip the bytes */
- ly_in_skip(lybctx->in, count_bytes);
+ LY_CHECK_GOTO(ly_in_skip(lybctx->in, count_bytes), eof);
}
}
}
@@ -144,6 +145,12 @@ lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
lybctx->buf = new_buf >> count_bits_remainder;
lybctx->buf_bits = 8 - count_bits_remainder;
}
+
+ return LY_SUCCESS;
+
+eof:
+ LOGERR(lybctx->ctx, LY_EVALID, "Unexpected end of LYB data.");
+ return LY_EVALID;
}
/**
@@ -151,8 +158,9 @@ lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
*
* @param[in,out] count Destination count buffer, must be zeroed because only relevant bits will be used.
* @param[in] lybctx LYB context.
+ * @return LY_ERR value.
*/
-static void
+static LY_ERR
lyb_read_count(uint32_t *count, struct lylyb_parse_ctx *lybctx)
{
uint8_t prefix = 0, pref_len = 0, byte_len = 0;
@@ -162,9 +170,9 @@ lyb_read_count(uint32_t *count, struct lylyb_parse_ctx *lybctx)
if (!lybctx->shrink) {
/* always use 2 bytes for the count */
byte_len = 2;
- lyb_read(&count16, byte_len * 8, lybctx);
+ LY_CHECK_RET(lyb_read(&count16, byte_len * 8, lybctx));
*count = le16toh(count16);
- return;
+ return LY_SUCCESS;
}
/* --- shrink mode ---
@@ -173,7 +181,7 @@ lyb_read_count(uint32_t *count, struct lylyb_parse_ctx *lybctx)
++pref_len;
prefix <<= 1;
- lyb_read(&prefix, 1, lybctx);
+ LY_CHECK_RET(lyb_read(&prefix, 1, lybctx));
} while (prefix & 0x1);
switch (pref_len) {
@@ -182,32 +190,34 @@ lyb_read_count(uint32_t *count, struct lylyb_parse_ctx *lybctx)
break;
case 2:
/* 10 */
- lyb_read(count, 4, lybctx);
+ LY_CHECK_RET(lyb_read(count, 4, lybctx));
break;
case 3:
/* 110 */
- lyb_read(count, 5, lybctx);
+ LY_CHECK_RET(lyb_read(count, 5, lybctx));
break;
case 4:
/* 1110 */
- lyb_read(count, 7, lybctx);
+ LY_CHECK_RET(lyb_read(count, 7, lybctx));
break;
case 5:
/* 11110 */
- lyb_read(count, 11, lybctx);
+ LY_CHECK_RET(lyb_read(count, 11, lybctx));
break;
case 6:
/* 111110 */
- lyb_read(count, 26, lybctx);
+ LY_CHECK_RET(lyb_read(count, 26, lybctx));
break;
default:
/* invalid */
- LOGINT(lybctx->ctx);
- return;
+ LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB count prefix.");
+ return LY_EVALID;
}
/* correct byte order */
*count = le32toh(*count);
+
+ return LY_SUCCESS;
}
/**
@@ -215,8 +225,9 @@ lyb_read_count(uint32_t *count, struct lylyb_parse_ctx *lybctx)
*
* @param[in,out] size Destination size buffer, must be zeroed because only relevant bits will be used.
* @param[in] lybctx LYB context.
+ * @return LY_ERR value.
*/
-static void
+static LY_ERR
lyb_read_size(uint32_t *size, struct lylyb_parse_ctx *lybctx)
{
uint8_t prefix = 0, pref_len = 0, byte_len = 0;
@@ -225,9 +236,9 @@ lyb_read_size(uint32_t *size, struct lylyb_parse_ctx *lybctx)
if (!lybctx->shrink) {
/* always use 4 bytes for the size */
byte_len = 4;
- lyb_read(size, byte_len * 8, lybctx);
+ LY_CHECK_RET(lyb_read(size, byte_len * 8, lybctx));
*size = le32toh(*size);
- return;
+ return LY_SUCCESS;
}
/* --- shrink mode ---
@@ -236,34 +247,36 @@ lyb_read_size(uint32_t *size, struct lylyb_parse_ctx *lybctx)
++pref_len;
prefix <<= 1;
- lyb_read(&prefix, 1, lybctx);
+ LY_CHECK_RET(lyb_read(&prefix, 1, lybctx));
} while (prefix & 0x1);
switch (pref_len) {
case 1:
/* 0 */
- lyb_read(size, 4, lybctx);
+ LY_CHECK_RET(lyb_read(size, 4, lybctx));
break;
case 2:
/* 10 */
- lyb_read(size, 6, lybctx);
+ LY_CHECK_RET(lyb_read(size, 6, lybctx));
break;
case 3:
/* 110 */
- lyb_read(size, 12, lybctx);
+ LY_CHECK_RET(lyb_read(size, 12, lybctx));
break;
case 4:
/* 1110 */
- lyb_read(size, 32, lybctx);
+ LY_CHECK_RET(lyb_read(size, 32, lybctx));
break;
default:
/* invalid */
- LOGINT(lybctx->ctx);
- return;
+ LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB size prefix.");
+ return LY_EVALID;
}
/* correct byte order */
*size = le32toh(*size);
+
+ return LY_SUCCESS;
}
/**
@@ -277,12 +290,13 @@ lyb_read_size(uint32_t *size, struct lylyb_parse_ctx *lybctx)
static LY_ERR
lyb_read_string(char **str, struct lylyb_parse_ctx *lybctx)
{
+ LY_ERR r;
uint32_t str_len = 0;
*str = NULL;
/* read length in bytes */
- lyb_read_size(&str_len, lybctx);
+ LY_CHECK_RET(lyb_read_size(&str_len, lybctx));
/* str_len + 1 wraps to 0 when str_len == UINT32_MAX, causing malloc(0) followed by an out-of-bounds write */
LY_CHECK_ERR_RET(str_len == UINT32_MAX, LOGERR(lybctx->ctx, LY_EINVAL, "LYB string length overflow."), LY_EINVAL);
@@ -293,7 +307,7 @@ lyb_read_string(char **str, struct lylyb_parse_ctx *lybctx)
if (str_len) {
/* read the string */
- lyb_read(*str, (uint64_t)str_len * 8, lybctx);
+ LY_CHECK_ERR_RET(r = lyb_read(*str, (uint64_t)str_len * 8, lybctx), free(*str); *str = NULL, r);
}
(*str)[str_len] = '\0';
@@ -312,6 +326,7 @@ lyb_read_string(char **str, struct lylyb_parse_ctx *lybctx)
static LY_ERR
lyb_read_value(const struct lysc_type *type, uint8_t **val, uint64_t *val_size_bits, struct lylyb_parse_ctx *lybctx)
{
+ LY_ERR r;
enum lyplg_lyb_size_type size_type;
uint32_t lyb_size_bits = 0;
uint64_t fixed_size_bits;
@@ -336,7 +351,7 @@ lyb_read_value(const struct lysc_type *type, uint8_t **val, uint64_t *val_size_b
*val_size_bits = fixed_size_bits;
} else {
/* parse value size in bits or bytes, uint32_t is enough because larger sizes will be stored as bytes */
- lyb_read_size(&lyb_size_bits, lybctx);
+ LY_CHECK_RET(lyb_read_size(&lyb_size_bits, lybctx));
*val_size_bits = lyb_size_bits;
if (size_type == LYPLG_LYB_SIZE_VARIABLE_BYTES) {
*val_size_bits *= 8;
@@ -354,7 +369,7 @@ lyb_read_value(const struct lysc_type *type, uint8_t **val, uint64_t *val_size_b
if (*val_size_bits > 0) {
/* parse value */
- lyb_read(*val, *val_size_bits, lybctx);
+ LY_CHECK_ERR_RET(r = lyb_read(*val, *val_size_bits, lybctx), free(*val); *val = NULL, r);
}
return LY_SUCCESS;
@@ -410,7 +425,7 @@ lyb_check_mod_features(struct lyd_lyb_ctx *lybctx, const char *mod_name, const s
uint32_t i, feature_count = 0, ctx_feature_count, len;
/* read feature count */
- lyb_read_count(&feature_count, pctx);
+ LY_CHECK_GOTO(rc = lyb_read_count(&feature_count, pctx), cleanup);
if (feature_count) {
/* create an array for the features */
@@ -448,6 +463,11 @@ lyb_check_mod_features(struct lyd_lyb_ctx *lybctx, const char *mod_name, const s
/* feature mismatch, prepare error message, unpack enabled features for printer */
len = 0;
for (i = 0; i < feature_count; i++) {
+ if ((uint64_t)len + strlen(features[i]) + 2 > UINT32_MAX - 1) {
+ LOGERR(pctx->ctx, LY_EINVAL, "Invalid enabled features of module \"%s\", too long.", mod_name);
+ rc = LY_EDENIED;
+ goto cleanup;
+ }
len += strlen(features[i]) + 2;
}
en_feats_printer = calloc(1, len + 1);
@@ -463,6 +483,11 @@ lyb_check_mod_features(struct lyd_lyb_ctx *lybctx, const char *mod_name, const s
len = 0;
ctx_feature_count = LY_ARRAY_COUNT(mod->compiled->features);
for (i = 0; i < ctx_feature_count; i++) {
+ if ((uint64_t)len + strlen(mod->compiled->features[i]) + 2 > UINT32_MAX - 1) {
+ LOGINT(pctx->ctx);
+ rc = LY_EINT;
+ goto cleanup;
+ }
len += strlen(mod->compiled->features[i]) + 2;
}
en_feats_parser = calloc(1, len + 1);
@@ -519,7 +544,7 @@ lyb_parse_module(struct lyd_lyb_ctx *lybctx, const struct lys_module **mod)
}
/* module revision */
- lyb_read(&rev, 2 * 8, pctx);
+ LY_CHECK_GOTO(rc = lyb_read(&rev, 2 * 8, pctx), cleanup);
if (rev) {
sprintf(mod_rev, "%04u-%02u-%02u", ((rev & LYB_REV_YEAR_MASK) >> LYB_REV_YEAR_SHIFT) + LYB_REV_YEAR_OFFSET,
(rev & LYB_REV_MONTH_MASK) >> LYB_REV_MONTH_SHIFT, rev & LYB_REV_DAY_MASK);
@@ -552,7 +577,7 @@ lyb_parse_module_idx(struct lyd_lyb_ctx *lybctx, const struct lys_module **mod)
uint32_t idx = 0;
/* read module index */
- lyb_read_count(&idx, pctx);
+ LY_CHECK_GOTO(rc = lyb_read_count(&idx, pctx), cleanup);
/* check the read index */
if (idx >= pctx->ctx->modules.count) {
@@ -602,9 +627,11 @@ lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent,
struct lysc_ext_instance *ant;
const struct lysc_type *ant_type;
+ *meta = NULL;
+
if (metadata_count == UINT32_MAX) {
/* reserved value meaning metadata count not read yet, read it now */
- lyb_read_count(&count, lybctx->parse_ctx);
+ LY_CHECK_GOTO(rc = lyb_read_count(&count, lybctx->parse_ctx), cleanup);
} else {
/* use provided count */
count = metadata_count;
@@ -672,7 +699,7 @@ lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent,
static LY_ERR
lyb_parse_prefix_data(struct lylyb_parse_ctx *lybctx, LY_VALUE_FORMAT format, void **prefix_data)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
uint32_t count = 0, i;
struct ly_set *set = NULL;
struct lyxml_ns *ns = NULL;
@@ -680,25 +707,26 @@ lyb_parse_prefix_data(struct lylyb_parse_ctx *lybctx, LY_VALUE_FORMAT format, vo
switch (format) {
case LY_VALUE_XML:
/* read count */
- lyb_read_count(&count, lybctx);
+ LY_CHECK_GOTO(rc = lyb_read_count(&count, lybctx), cleanup);
/* read all NS elements */
- LY_CHECK_GOTO(ret = ly_set_new(&set), cleanup);
+ LY_CHECK_GOTO(rc = ly_set_new(&set), cleanup);
for (i = 0; i < count; ++i) {
ns = calloc(1, sizeof *ns);
+ LY_CHECK_ERR_GOTO(!ns, LOGMEM(lybctx->ctx); rc = LY_EMEM, cleanup);
/* prefix */
- LY_CHECK_GOTO(ret = lyb_read_string(&ns->prefix, lybctx), cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&ns->prefix, lybctx), cleanup);
if (!strlen(ns->prefix)) {
free(ns->prefix);
ns->prefix = NULL;
}
/* namespace */
- LY_CHECK_GOTO(ret = lyb_read_string(&ns->uri, lybctx), cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&ns->uri, lybctx), cleanup);
- LY_CHECK_GOTO(ret = ly_set_add(set, ns, 1, NULL), cleanup);
+ LY_CHECK_GOTO(rc = ly_set_add(set, ns, 1, NULL), cleanup);
ns = NULL;
}
@@ -710,12 +738,12 @@ lyb_parse_prefix_data(struct lylyb_parse_ctx *lybctx, LY_VALUE_FORMAT format, vo
break;
default:
LOGINT(lybctx->ctx);
- ret = LY_EINT;
+ rc = LY_EINT;
break;
}
cleanup:
- if (ret) {
+ if (rc) {
ly_free_prefix_data(format, set);
if (ns) {
free(ns->prefix);
@@ -723,7 +751,7 @@ lyb_parse_prefix_data(struct lylyb_parse_ctx *lybctx, LY_VALUE_FORMAT format, vo
free(ns);
}
}
- return ret;
+ return rc;
}
/**
@@ -736,7 +764,7 @@ lyb_parse_prefix_data(struct lylyb_parse_ctx *lybctx, LY_VALUE_FORMAT format, vo
static LY_ERR
lyb_parse_attributes(struct lylyb_parse_ctx *lybctx, struct lyd_attr **attr)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
uint32_t count = 0, i;
struct lyd_attr *attr2 = NULL;
char *prefix = NULL, *module_name = NULL, *name = NULL, *value = NULL;
@@ -745,33 +773,32 @@ lyb_parse_attributes(struct lylyb_parse_ctx *lybctx, struct lyd_attr **attr)
void *val_prefix_data = NULL;
uint8_t byte = 0;
+ *attr = NULL;
+
/* read count */
- lyb_read_count(&count, lybctx);
+ LY_CHECK_GOTO(rc = lyb_read_count(&count, lybctx), cleanup);
/* read attributes */
for (i = 0; i < count; ++i) {
/* prefix, may be empty */
- ret = lyb_read_string(&prefix, lybctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&prefix, lybctx), cleanup);
if (!prefix[0]) {
free(prefix);
prefix = NULL;
}
/* namespace, may be empty */
- ret = lyb_read_string(&module_name, lybctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&module_name, lybctx), cleanup);
if (!module_name[0]) {
free(module_name);
module_name = NULL;
}
/* name */
- ret = lyb_read_string(&name, lybctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&name, lybctx), cleanup);
/* format */
- lyb_read(&byte, LYB_OPAQ_FORMAT_BITS, lybctx);
+ LY_CHECK_GOTO(rc = lyb_read(&byte, LYB_OPAQ_FORMAT_BITS, lybctx), cleanup);
if (byte == LYB_OPAQ_FORMAT_XML) {
format = LY_VALUE_XML;
} else {
@@ -780,18 +807,17 @@ lyb_parse_attributes(struct lylyb_parse_ctx *lybctx, struct lyd_attr **attr)
}
/* value prefixes */
- ret = lyb_parse_prefix_data(lybctx, format, &val_prefix_data);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_parse_prefix_data(lybctx, format, &val_prefix_data), cleanup);
/* value */
- ret = lyb_read_string(&value, lybctx);
- LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
+ rc = lyb_read_string(&value, lybctx);
+ LY_CHECK_ERR_GOTO(rc, ly_free_prefix_data(format, val_prefix_data), cleanup);
dynamic = 1;
/* attr2 is always changed to the created attribute */
- ret = lyd_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), prefix, ly_strlen(prefix), module_name,
+ rc = lyd_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), prefix, ly_strlen(prefix), module_name,
ly_strlen(module_name), value, ly_strlen(value), &dynamic, format, val_prefix_data, LYD_HINT_DATA);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc, cleanup);
free(prefix);
prefix = NULL;
@@ -805,8 +831,6 @@ lyb_parse_attributes(struct lylyb_parse_ctx *lybctx, struct lyd_attr **attr)
if (!*attr) {
*attr = attr2;
}
-
- LY_CHECK_GOTO(ret, cleanup);
}
cleanup:
@@ -816,11 +840,11 @@ lyb_parse_attributes(struct lylyb_parse_ctx *lybctx, struct lyd_attr **attr)
if (dynamic) {
free(value);
}
- if (ret) {
+ if (rc) {
lyd_free_attr_siblings(lybctx->ctx, *attr);
*attr = NULL;
}
- return ret;
+ return rc;
}
/**
@@ -837,7 +861,7 @@ lyb_read_hashes(struct lylyb_parse_ctx *lybctx, LYB_HASH *hash, uint8_t *hash_co
uint8_t i = 0, j;
/* read the first hash */
- lyb_read(&hash[0], sizeof *hash * 8, lybctx);
+ LY_CHECK_RET(lyb_read(&hash[0], sizeof *hash * 8, lybctx));
if (!hash[0]) {
*hash_count = i + 1;
@@ -846,7 +870,7 @@ lyb_read_hashes(struct lylyb_parse_ctx *lybctx, LYB_HASH *hash, uint8_t *hash_co
/* based on the first hash read all the other ones, if any */
for (i = 0; !(hash[0] & (LYB_HASH_COLLISION_ID >> i)); ++i) {
- if (i > LYB_HASH_BITS) {
+ if (i == LYB_HASH_BITS) {
LOGINT_RET(lybctx->ctx);
}
}
@@ -856,12 +880,18 @@ lyb_read_hashes(struct lylyb_parse_ctx *lybctx, LYB_HASH *hash, uint8_t *hash_co
/* read the rest of hashes */
for (j = i; j; --j) {
- lyb_read(&hash[j - 1], sizeof *hash * 8, lybctx);
+ LY_CHECK_RET(lyb_read(&hash[j - 1], sizeof *hash * 8, lybctx));
/* correct collision ID */
- assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
+ if (!(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)))) {
+ LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB schema hash collision ID.");
+ return LY_EVALID;
+ }
/* preceded with zeros */
- assert(!(hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))));
+ if (hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))) {
+ LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB schema hash prefix.");
+ return LY_EVALID;
+ }
}
*hash_count = i + 1;
@@ -910,7 +940,7 @@ lyb_parse_schema_hash(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparen
{
LY_ERR r;
const struct lysc_node *sibling;
- LYB_HASH hash[LYB_HASH_BITS - 1];
+ LYB_HASH hash[LYB_HASH_BITS];
uint32_t getnext_opts;
uint8_t hash_count;
@@ -1001,35 +1031,6 @@ lyb_parse_schema_ext(struct lyd_lyb_ctx *lybctx, const struct lyd_node *parent,
return rc;
}
-/**
- * @brief Insert new node to @p parsed set.
- *
- * Also if needed, correct @p first_p.
- *
- * @param[in] lybctx LYB context.
- * @param[in] parent Data parent of the sibling, must be set if @p first_p is not.
- * @param[in,out] node Parsed node to insertion.
- * @param[in,out] first_p First top-level sibling, must be set if @p parent is not.
- * @param[out] parsed Set of all successfully parsed nodes.
- * @return LY_ERR value.
- */
-static void
-lyb_insert_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_node *node, struct lyd_node **first_p,
- struct ly_set *parsed)
-{
- /* insert, keep first pointer correct */
- lyd_insert_node(parent, first_p, node,
- lybctx->parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT);
- while (!parent && (*first_p)->prev->next) {
- *first_p = (*first_p)->prev;
- }
-
- /* rememeber a successfully parsed node */
- if (parsed) {
- ly_set_add(parsed, node, 1, NULL);
- }
-}
-
/**
* @brief Finish parsing the opaq node.
*
@@ -1041,7 +1042,7 @@ lyb_insert_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_
* @param[out] parsed Set of all successfully parsed nodes.
* @return LY_ERR value.
*/
-static void
+static LY_ERR
lyb_finish_opaq(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_attr **attr, struct lyd_node **node,
struct lyd_node **first_p, struct ly_set *parsed)
{
@@ -1055,53 +1056,56 @@ lyb_finish_opaq(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_
((struct lyd_node_opaq *)*node)->attr = *attr;
*attr = NULL;
- lyb_insert_node(lybctx, parent, *node, first_p, parsed);
+ LY_CHECK_RET(lyd_parser_node_insert(parent, first_p, NULL, lybctx->parse_opts, *node));
+
+ /* rememeber a successfully parsed node */
+ if (parsed) {
+ ly_set_add(parsed, *node, 1, NULL);
+ }
+
*node = NULL;
+
+ return LY_SUCCESS;
}
/**
* @brief Finish parsing the node.
*
* @param[in] lybctx LYB context.
- * @param[in] parent Data parent of the sibling, must be set if @p first_p is not.
- * @param[in] flags Node flags to set.
+ * @param[in] node Parsed node to finish.
* @param[in] ext Ext instance of @p node, if any.
* @param[in,out] meta Metadata to be attached. Finally set to NULL.
- * @param[in,out] node Parsed node to finish.
- * @param[in,out] first_p First top-level sibling, must be set if @p parent is not.
* @param[out] parsed Set of all successfully parsed nodes.
* @return LY_ERR value.
*/
static LY_ERR
-lyb_finish_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, uint32_t flags, const struct lysc_ext_instance *ext,
- struct lyd_meta **meta, struct lyd_node **node, struct lyd_node **first_p, struct ly_set *parsed)
+lyb_finish_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *node, const struct lysc_ext_instance *ext,
+ struct lyd_meta **meta, struct ly_set *parsed)
{
struct lyd_meta *m;
- /* set flags */
- (*node)->flags = flags;
-
/* add metadata */
LY_LIST_FOR(*meta, m) {
- m->parent = *node;
+ m->parent = node;
}
- (*node)->meta = *meta;
+ node->meta = *meta;
*meta = NULL;
- /* insert into parent */
- lyb_insert_node(lybctx, parent, *node, first_p, parsed);
-
if (!(lybctx->parse_opts & LYD_PARSE_ONLY)) {
if (ext) {
/* parsed for an extension, validate the subtree using the same extension */
- LY_CHECK_RET(lyd_validate_tree_ext(*node, ext, &lybctx->ext_val));
+ LY_CHECK_RET(lyd_validate_tree_ext(node, ext, &lybctx->ext_val));
}
/* store for ext instance node validation, if needed */
- LY_CHECK_RET(lyd_validate_node_ext(*node, &lybctx->ext_val));
+ LY_CHECK_RET(lyd_validate_node_ext(node, &lybctx->ext_val));
+ }
+
+ /* rememeber a successfully parsed node */
+ if (parsed) {
+ ly_set_add(parsed, node, 1, NULL);
}
- *node = NULL;
return LY_SUCCESS;
}
@@ -1124,7 +1128,7 @@ lyb_parse_node_header(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparen
if (!lybctx->parse_ctx->shrink) {
/* read flags, fixed bits */
- lyb_read(flags, LYB_DATA_NODE_FLAG_BITS, lybctx->parse_ctx);
+ LY_CHECK_RET(lyb_read(flags, LYB_DATA_NODE_FLAG_BITS, lybctx->parse_ctx));
/* correct byte order */
*flags = le32toh(*flags);
@@ -1203,7 +1207,7 @@ lyb_validate_node_inner(struct lyd_lyb_ctx *lybctx, struct lyd_node *node)
static LY_ERR
lyb_parse_node_opaq(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
{
- LY_ERR ret;
+ LY_ERR rc = LY_SUCCESS;
struct lyd_node *node = NULL;
struct lyd_attr *attr = NULL;
char *value = NULL, *name = NULL, *prefix = NULL, *module_key = NULL;
@@ -1214,28 +1218,23 @@ lyb_parse_node_opaq(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct
const struct ly_ctx *ctx = lybctx->parse_ctx->ctx;
/* parse opaq node attributes */
- ret = lyb_parse_attributes(lybctx->parse_ctx, &attr);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_parse_attributes(lybctx->parse_ctx, &attr), cleanup);
/* parse prefix */
- ret = lyb_read_string(&prefix, lybctx->parse_ctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&prefix, lybctx->parse_ctx), cleanup);
/* parse module key */
- ret = lyb_read_string(&module_key, lybctx->parse_ctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&module_key, lybctx->parse_ctx), cleanup);
/* parse name */
- ret = lyb_read_string(&name, lybctx->parse_ctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&name, lybctx->parse_ctx), cleanup);
/* parse value */
- ret = lyb_read_string(&value, lybctx->parse_ctx);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&value, lybctx->parse_ctx), cleanup);
dynamic = 1;
/* parse format */
- lyb_read(&byte, LYB_OPAQ_FORMAT_BITS, lybctx->parse_ctx);
+ LY_CHECK_GOTO(rc = lyb_read(&byte, LYB_OPAQ_FORMAT_BITS, lybctx->parse_ctx), cleanup);
if (byte == LYB_OPAQ_FORMAT_XML) {
format = LY_VALUE_XML;
} else {
@@ -1244,21 +1243,19 @@ lyb_parse_node_opaq(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct
}
/* parse value prefixes */
- ret = lyb_parse_prefix_data(lybctx->parse_ctx, format, &val_prefix_data);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_parse_prefix_data(lybctx->parse_ctx, format, &val_prefix_data), cleanup);
/* create node */
- ret = lyd_create_opaq(ctx, name, strlen(name), prefix, ly_strlen(prefix), module_key, ly_strlen(module_key),
+ rc = lyd_create_opaq(ctx, name, strlen(name), prefix, ly_strlen(prefix), module_key, ly_strlen(module_key),
value, strlen(value), &dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
- LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
+ LY_CHECK_ERR_GOTO(rc, ly_free_prefix_data(format, val_prefix_data), cleanup);
/* process children */
- ret = lyb_parse_siblings(lybctx, node, 0, NULL, NULL);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyb_parse_siblings(lybctx, node, 0, parent, NULL, NULL), cleanup);
if (lybctx->parse_opts & LYD_PARSE_OPAQ) {
/* register parsed opaq node */
- lyb_finish_opaq(lybctx, parent, &attr, &node, first_p, parsed);
+ LY_CHECK_GOTO(rc = lyb_finish_opaq(lybctx, parent, &attr, &node, first_p, parsed), cleanup);
assert(!attr && !node);
} /* else is freed */
@@ -1272,7 +1269,7 @@ lyb_parse_node_opaq(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct
lyd_free_attr_siblings(ctx, attr);
lyd_free_tree(node);
- return ret;
+ return rc;
}
/**
@@ -1298,11 +1295,10 @@ lyb_parse_node_any(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const st
const struct ly_ctx *ctx = lybctx->parse_ctx->ctx;
/* read necessary basic data */
- rc = lyb_parse_node_header(lybctx, snode, UINT32_MAX, &flags, &meta);
- LY_CHECK_GOTO(rc, cleanup);
+ LY_CHECK_GOTO(rc = lyb_parse_node_header(lybctx, snode, UINT32_MAX, &flags, &meta), cleanup);
/* parse value type */
- lyb_read_count((uint32_t *)&value_type, lybctx->parse_ctx);
+ LY_CHECK_GOTO(rc = lyb_read_count((uint32_t *)&value_type, lybctx->parse_ctx), cleanup);
/* create the node */
if (value_type == 0) {
@@ -1313,23 +1309,20 @@ lyb_parse_node_any(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const st
lybctx->int_opts = LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
/* parse LYB siblings, restore options */
- rc = lyb_parse_siblings(lybctx, NULL, 0, &tree, NULL);
+ rc = lyb_parse_siblings(lybctx, NULL, 0, NULL, &tree, NULL);
lybctx->parse_opts = prev_parse_opts;
lybctx->int_opts = prev_int_opts;
LY_CHECK_GOTO(rc, cleanup);
/* use the data tree value */
- rc = lyd_create_any(snode, tree, NULL, 0, 1, 0, &node);
- LY_CHECK_GOTO(rc, cleanup);
+ LY_CHECK_GOTO(rc = lyd_create_any(snode, tree, NULL, 0, 1, 0, &node), cleanup);
tree = NULL;
} else if (value_type == 1) {
/* string value */
- rc = lyb_read_string(&value, lybctx->parse_ctx);
- LY_CHECK_GOTO(rc, cleanup);
+ LY_CHECK_GOTO(rc = lyb_read_string(&value, lybctx->parse_ctx), cleanup);
/* use the string value */
- rc = lyd_create_any(snode, NULL, value, 0, 1, 0, &node);
- LY_CHECK_GOTO(rc, cleanup);
+ LY_CHECK_GOTO(rc = lyd_create_any(snode, NULL, value, 0, 1, 0, &node), cleanup);
value = NULL;
} else {
LOGINT(ctx);
@@ -1337,15 +1330,20 @@ lyb_parse_node_any(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const st
goto cleanup;
}
- /* register parsed anydata node */
- rc = lyb_finish_node(lybctx, parent, flags, ext, &meta, &node, first_p, parsed);
- LY_CHECK_GOTO(rc, cleanup);
+ /* insert, needs LYD_EXT flag */
+ node->flags = flags;
+ LY_CHECK_GOTO(rc = lyd_parser_node_insert(parent, first_p, NULL, lybctx->parse_opts, node), cleanup);
+
+ /* finish parsed anydata node */
+ LY_CHECK_GOTO(rc = lyb_finish_node(lybctx, node, ext, &meta, parsed), cleanup);
cleanup:
lyd_free_meta_siblings(meta);
lyd_free_siblings(tree);
free(value);
- lyd_free_tree(node);
+ if (rc) {
+ lyd_parser_node_free(first_p, &node);
+ }
return rc;
}
@@ -1377,8 +1375,13 @@ lyb_parse_node_inner(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const
rc = lyd_create_inner(snode, &node);
LY_CHECK_GOTO(rc, cleanup);
+ /* insert, needs LYD_EXT flag */
+ node->flags = flags;
+ rc = lyd_parser_node_insert(parent, first_p, NULL, lybctx->parse_opts, node);
+ LY_CHECK_GOTO(rc, cleanup);
+
/* process children */
- rc = lyb_parse_siblings(lybctx, node, 0, NULL, NULL);
+ rc = lyb_parse_siblings(lybctx, node, 0, parent, NULL, NULL);
LY_CHECK_GOTO(rc, cleanup);
/* additional procedure for inner node */
@@ -1390,13 +1393,15 @@ lyb_parse_node_inner(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const
lybctx->op_node = node;
}
- /* register parsed node */
- rc = lyb_finish_node(lybctx, parent, flags, ext, &meta, &node, first_p, parsed);
+ /* finish parsed node */
+ rc = lyb_finish_node(lybctx, node, ext, &meta, parsed);
LY_CHECK_GOTO(rc, cleanup);
cleanup:
lyd_free_meta_siblings(meta);
- lyd_free_tree(node);
+ if (rc) {
+ lyd_parser_node_free(first_p, &node);
+ }
return rc;
}
@@ -1429,12 +1434,20 @@ lyb_parse_node_leaf(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const s
rc = lyb_create_term(lybctx, snode, parent, &node);
LY_CHECK_GOTO(rc, cleanup);
- rc = lyb_finish_node(lybctx, parent, flags, ext, &meta, &node, first_p, parsed);
+ /* insert, needs LYD_EXT flag */
+ node->flags = flags;
+ rc = lyd_parser_node_insert(parent, first_p, NULL, lybctx->parse_opts, node);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ /* finish parsed node */
+ rc = lyb_finish_node(lybctx, node, ext, &meta, parsed);
LY_CHECK_GOTO(rc, cleanup);
cleanup:
lyd_free_meta_siblings(meta);
- lyd_free_tree(node);
+ if (rc) {
+ lyd_parser_node_free(first_p, &node);
+ }
return rc;
}
@@ -1457,7 +1470,7 @@ lyb_parse_node_leaflist(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, con
while (1) {
/* read metadata count to check for end of instances */
metadata_count = 0;
- lyb_read_count(&metadata_count, lybctx->parse_ctx);
+ LY_CHECK_RET(lyb_read_count(&metadata_count, lybctx->parse_ctx));
if (metadata_count == LYB_METADATA_END_COUNT) {
/* all the instances parsed */
break;
@@ -1493,7 +1506,7 @@ lyb_parse_node_list(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const s
while (1) {
/* read metadata count to check for end of instances */
metadata_count = 0;
- lyb_read_count(&metadata_count, lybctx->parse_ctx);
+ LY_CHECK_RET(lyb_read_count(&metadata_count, lybctx->parse_ctx));
if (metadata_count == LYB_METADATA_END_COUNT) {
/* all the instances parsed */
break;
@@ -1507,8 +1520,15 @@ lyb_parse_node_list(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const s
rc = lyd_create_inner(snode, &node);
LY_CHECK_GOTO(rc, cleanup);
+ /* cannot insert yet, will be inserted right after all the keys are parsed */
+ node->flags = flags;
+
/* process children */
- rc = lyb_parse_siblings(lybctx, node, 0, NULL, NULL);
+ rc = lyb_parse_siblings(lybctx, node, 0, parent, NULL, NULL);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ /* try to insert again, top-level list needs to be assigned to first_p */
+ rc = lyd_parser_node_insert(parent, first_p, NULL, lybctx->parse_opts, node);
LY_CHECK_GOTO(rc, cleanup);
/* additional procedure for inner node */
@@ -1520,14 +1540,16 @@ lyb_parse_node_list(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, const s
lybctx->op_node = node;
}
- /* register parsed list node */
- rc = lyb_finish_node(lybctx, parent, flags, ext, &meta, &node, first_p, parsed);
+ /* finish parsed list node */
+ rc = lyb_finish_node(lybctx, node, ext, &meta, parsed);
LY_CHECK_GOTO(rc, cleanup);
}
cleanup:
lyd_free_meta_siblings(meta);
- lyd_free_tree(node);
+ if (rc) {
+ lyd_parser_node_free(first_p, &node);
+ }
return rc;
}
@@ -1552,7 +1574,7 @@ lyb_parse_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_n
enum lylyb_node_type lyb_type = 0;
/* read node type */
- lyb_read(&lyb_type, LYB_NODE_TYPE_BITS, lybctx->parse_ctx);
+ LY_CHECK_GOTO(rc = lyb_read(&lyb_type, LYB_NODE_TYPE_BITS, lybctx->parse_ctx), cleanup);
/* correct byte order */
lyb_type = le32toh(lyb_type);
@@ -1584,6 +1606,10 @@ lyb_parse_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_n
/* read schema node name, find the ext schema node */
LY_CHECK_GOTO(rc = lyb_parse_schema_ext(lybctx, parent, mod->name, &snode, &ext), cleanup);
break;
+ default:
+ LOGERR(lybctx->parse_ctx->ctx, LY_EINVAL, "Invalid LYB node type 0x%x.", (int)lyb_type);
+ rc = LY_EINVAL;
+ goto cleanup;
}
if (!snode) {
@@ -1609,28 +1635,42 @@ lyb_parse_node(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_n
* @brief Parse siblings (@ref lyb_print_siblings()).
*
* @param[in] lybctx LYB context.
- * @param[in] parent Data parent of the sibling, must be set if @p first_p is not.
+ * @param[in] parent Data parent node of the sibling, must be set if @p first_p is not.
* @param[in] is_root Whether we are parsing the root node or not.
+ * @param[in] pparent Parent of @p parent.
* @param[in,out] first_p First top-level sibling, must be set if @p parent is not.
* @param[out] parsed Set of all successfully parsed nodes.
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_siblings(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, ly_bool is_root, struct lyd_node **first_p,
- struct ly_set *parsed)
+lyb_parse_siblings(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, ly_bool is_root, struct lyd_node *pparent,
+ struct lyd_node **first_p, struct ly_set *parsed)
{
LY_ERR r;
+ struct lylyb_parse_ctx *pctx = lybctx->parse_ctx;
+
+ ++pctx->depth;
+ if (pctx->depth == LY_MAX_BLOCK_DEPTH) {
+ LOGERR(pctx->ctx, LY_EINVAL, "Maximum number %d of block nestings has been exceeded.", LY_MAX_BLOCK_DEPTH);
+ return LY_EINVAL;
+ }
while (!(r = lyb_parse_node(lybctx, parent, first_p, parsed))) {
/* parsing some data, hash must be set */
assert(!lybctx->parse_ctx->empty_hash);
+ if (pparent) {
+ /* insert again, node may be a list that had its keys missing */
+ LY_CHECK_RET(lyd_parser_node_insert(pparent, first_p, NULL, lybctx->parse_opts, parent));
+ }
+
if (is_root && !(lybctx->int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
break;
}
}
LY_CHECK_RET(r != LY_ENOT, r);
+ --pctx->depth;
return LY_SUCCESS;
}
@@ -1650,7 +1690,7 @@ lyb_parse_context_hash(struct lyd_lyb_ctx *lybctx)
/* context hash */
data_hash = 0;
- lyb_read((uint8_t *)&data_hash, LYB_HEADER_CTX_HASH_BITS, pctx);
+ LY_CHECK_RET(lyb_read((uint8_t *)&data_hash, LYB_HEADER_CTX_HASH_BITS, pctx));
/* correct byte order */
data_hash = le32toh(data_hash);
@@ -1690,7 +1730,7 @@ lyb_parse_header(struct lyd_lyb_ctx *lybctx)
/* version */
byte = 0;
- lyb_read(&byte, LYB_HEADER_VERSION_BITS, pctx);
+ LY_CHECK_RET(lyb_read(&byte, LYB_HEADER_VERSION_BITS, pctx));
if (byte != LYB_HEADER_VERSION_NUM) {
LOGERR(pctx->ctx, LY_EINVAL, "Invalid LYB format version \"0x%" PRIx8 "\", expected \"0x%x\".",
byte, LYB_HEADER_VERSION_NUM);
@@ -1699,7 +1739,7 @@ lyb_parse_header(struct lyd_lyb_ctx *lybctx)
/* hash algorithm */
byte = 0;
- lyb_read(&byte, LYB_HEADER_HASH_ALG_BITS, pctx);
+ LY_CHECK_RET(lyb_read(&byte, LYB_HEADER_HASH_ALG_BITS, pctx));
if (byte != LYB_HEADER_HASH_ALG_NUM) {
LOGERR(pctx->ctx, LY_EINVAL, "Different LYB format hash algorithm \"0x%" PRIx8 "\" used, expected \"0x%x\".",
byte, LYB_HEADER_HASH_ALG_NUM);
@@ -1708,13 +1748,13 @@ lyb_parse_header(struct lyd_lyb_ctx *lybctx)
/* shrink */
byte = 0;
- lyb_read(&byte, LYB_HEADER_SHRINK_FLAG_BITS, pctx);
+ LY_CHECK_RET(lyb_read(&byte, LYB_HEADER_SHRINK_FLAG_BITS, pctx));
is_shrink = byte;
/* read and check remaining reserved bits */
remaining_bit_count = 8 - (LYB_HEADER_VERSION_BITS + LYB_HEADER_HASH_ALG_BITS + LYB_HEADER_SHRINK_FLAG_BITS);
byte = 0;
- lyb_read(&byte, remaining_bit_count, pctx);
+ LY_CHECK_RET(lyb_read(&byte, remaining_bit_count, pctx));
if (byte) {
LOGERR(pctx->ctx, LY_EINVAL, "Invalid reserved bits in LYB header.");
return LY_EINVAL;
@@ -1765,7 +1805,7 @@ lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node
LY_CHECK_GOTO(rc, cleanup);
/* read sibling(s) */
- rc = lyb_parse_siblings(lybctx, parent, 1, first_p, parsed);
+ rc = lyb_parse_siblings(lybctx, parent, 1, NULL, first_p, parsed);
LY_CHECK_GOTO(rc, cleanup);
if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lybctx->op_node) {
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 0f00ad67d8..a2f019825a 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -579,12 +579,17 @@ lydxml_subtree_get_snode(struct lyd_xml_ctx *lydctx, const struct lyd_node *pare
*ext = NULL;
/* try to find parent schema node */
- if (parent && parent->schema && !(parent->schema->nodetype & LYD_NODE_ANY)) {
+ if (parent && parent->schema) {
/* use only a schema parent */
sparent = parent->schema;
} else {
sparent = NULL;
}
+ if (sparent && (sparent->nodetype & LYD_NODE_ANY)) {
+ /* do not search in children, module is inherited by default (namespace) */
+ sparent = NULL;
+ }
+
if (!prefix_len) {
prefix = NULL;
}
@@ -769,23 +774,25 @@ lydxml_subtree_term(struct lyd_xml_ctx *lydctx, const struct lysc_node *snode, c
&xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, node);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
- /* insert, needs LYD_EXT flag */
- if (ext) {
- (*node)->flags |= LYD_EXT;
- }
- r = lyd_parser_node_insert(parent, first_p, NULL, lydctx->parse_opts, *node);
- LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ if (*node) {
+ /* insert, needs LYD_EXT flag */
+ if (ext) {
+ (*node)->flags |= LYD_EXT;
+ }
+ r = lyd_parser_node_insert(parent, first_p, NULL, lydctx->parse_opts, *node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
- if (*node && parent && (snode->flags & LYS_KEY)) {
- /* check the key order, the anchor must never be a key */
- anchor = lyd_insert_get_next_anchor(lyd_child(parent), *node);
- if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
- if (lydctx->parse_opts & LYD_PARSE_STRICT) {
- LOGVAL(xmlctx->ctx, *node, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", snode->name);
- r = LY_EVALID;
- LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
- } else {
- LOGWRN(xmlctx->ctx, "Invalid position of the key \"%s\" in a list.", snode->name);
+ if (parent && (snode->flags & LYS_KEY)) {
+ /* check the key order, the anchor must never be a key */
+ anchor = lyd_insert_get_next_anchor(lyd_child(parent), *node);
+ if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
+ if (lydctx->parse_opts & LYD_PARSE_STRICT) {
+ LOGVAL(xmlctx->ctx, *node, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", snode->name);
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ } else {
+ LOGWRN(xmlctx->ctx, "Invalid position of the key \"%s\" in a list.", snode->name);
+ }
}
}
}
diff --git a/src/parser_yang.c b/src/parser_yang.c
index dd4c59029d..2a7de21f96 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -303,6 +303,43 @@ skip_comment(struct lysp_yang_ctx *ctx, uint8_t comment)
#undef COMMENT_BLOCK_END
}
+/**
+ * @brief Read from a replacement string instead of standard input.
+ *
+ * DOES NOT MOVE THE INPUT!
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] arg Type of YANG keyword argument expected.
+ * @param[in] tmp_input Temporary input string to use for reading the char.
+ * @param[out] word_p Pointer to the read quoted string.
+ * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read quoted string. If not needed,
+ * set to NULL. Otherwise equal to @p word_p.
+ * @param[out] word_len Length of the read quoted string.
+ * @param[out] buf_len Length of the dynamically-allocated buffer @p word_b.
+ * @return LY_ERR values.
+ */
+static LY_ERR
+buf_store_char_replaced_input(struct lysp_yang_ctx *ctx, enum yang_arg arg, const char *tmp_input, char **word_p,
+ char **word_b, size_t *word_len, size_t *buf_len)
+{
+ LY_ERR rc = LY_SUCCESS;
+ const char *c, *s;
+
+ /* backup */
+ c = ctx->in->current;
+ s = ctx->in->start;
+
+ /* read the special non-input string (char) */
+ ctx->in->current = ctx->in->start = tmp_input;
+ rc = buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, 1, NULL);
+
+ /* restore */
+ ctx->in->current = c;
+ ctx->in->start = s;
+
+ return rc;
+}
+
/**
* @brief Read a quoted string from data.
*
@@ -310,11 +347,9 @@ skip_comment(struct lysp_yang_ctx *ctx, uint8_t comment)
* @param[in] arg Type of YANG keyword argument expected.
* @param[out] word_p Pointer to the read quoted string.
* @param[out] word_b Pointer to a dynamically-allocated buffer holding the read quoted string. If not needed,
- * set to NULL. Otherwise equal to \p word_p.
+ * set to NULL. Otherwise equal to @p word_p.
* @param[out] word_len Length of the read quoted string.
- * @param[out] buf_len Length of the dynamically-allocated buffer \p word_b.
- * @param[in] indent Current indent (number of YANG spaces). Needed for correct multi-line string
- * indenation in the final quoted string.
+ * @param[out] buf_len Length of the dynamically-allocated buffer @p word_b.
* @return LY_ERR values.
*/
static LY_ERR
@@ -333,7 +368,6 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
uint64_t block_indent = 0, current_indent = 0;
ly_bool need_buf = 0;
uint8_t prefix = 0;
- const char *c;
uint64_t trailing_ws = 0; /* current number of stored trailing whitespace characters */
if (ctx->in->current[0] == '\"') {
@@ -399,10 +433,7 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
ctx->indent += Y_TAB_SPACES;
for ( ; current_indent > block_indent; --current_indent, --ctx->indent) {
/* store leftover spaces from the tab */
- c = ctx->in->current;
- ctx->in->current = " ";
- LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
- ctx->in->current = c;
+ LY_CHECK_RET(buf_store_char_replaced_input(ctx, arg, " ", word_p, word_b, word_len, buf_len));
trailing_ws++;
}
++ctx->in->current;
@@ -434,18 +465,14 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
current_indent = 0;
}
- c = NULL;
- if (ctx->in->current[0] != '\n') {
+ if (ctx->in->current[0] == '\n') {
+ /* check and store character */
+ LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
+ } else {
/* storing '\r' as '\n' */
- c = ctx->in->current;
- ctx->in->current = "\n";
- }
-
- /* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
-
- if (c) {
- ctx->in->current = c + 1;
+ need_buf = 1;
+ LY_CHECK_RET(buf_store_char_replaced_input(ctx, arg, "\n", word_p, word_b, word_len, buf_len));
+ ++ctx->in->current;
}
/* reset context indentation counter for possible string after this one */
@@ -464,19 +491,23 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
break;
case STRING_DOUBLE_QUOTED_ESCAPED:
/* string encoded characters */
- c = ctx->in->current;
switch (ctx->in->current[0]) {
case 'n':
- ctx->in->current = "\n";
+ need_buf = 1;
/* fix false newline count in buf_store_char() */
ctx->in->line--;
+ LY_CHECK_RET(buf_store_char_replaced_input(ctx, arg, "\n", word_p, word_b, word_len, buf_len));
+ ++ctx->in->current;
break;
case 't':
- ctx->in->current = "\t";
+ need_buf = 1;
+ LY_CHECK_RET(buf_store_char_replaced_input(ctx, arg, "\t", word_p, word_b, word_len, buf_len));
+ ++ctx->in->current;
break;
case '\"':
case '\\':
- /* ok as is */
+ /* ok as is, check and store character */
+ LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
break;
default:
LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Double-quoted string unknown special character '\\%c'.",
@@ -484,11 +515,8 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
return LY_EVALID;
}
- /* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
-
+ /* escaped char processed */
string = STRING_DOUBLE_QUOTED;
- ctx->in->current = c + 1;
break;
case STRING_PAUSED_NEXTSTRING:
switch (ctx->in->current[0]) {
@@ -819,7 +847,7 @@ get_keyword(struct lysp_yang_ctx *ctx, enum ly_stmt *kw, char **word_p, size_t *
} else if (*kw == LY_STMT_SYNTAX_LEFT_BRACE) {
ctx->depth++;
if (ctx->depth > LY_MAX_BLOCK_DEPTH) {
- LOGERR(PARSER_CTX(ctx), LY_EINVAL, "The maximum number of block nestings has been exceeded.");
+ LOGERR(PARSER_CTX(ctx), LY_EINVAL, "Maximum number %d of block nestings has been exceeded.", LY_MAX_BLOCK_DEPTH);
return LY_EINVAL;
}
goto success;
diff --git a/src/path.c b/src/path.c
index ec8443adef..273a90009d 100644
--- a/src/path.c
+++ b/src/path.c
@@ -55,6 +55,7 @@ ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_no
struct ly_set *set = NULL;
uint32_t i;
const char *name;
+ char *start, *end;
size_t name_len;
if (cur_node) {
@@ -152,10 +153,11 @@ ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_no
} else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
/* Number */
- /* check for index 0 */
- if (!atoi(exp->expr + exp->tok_pos[*tok_idx - 1])) {
+ /* check for index 0 or fractions */
+ start = exp->expr + exp->tok_pos[*tok_idx - 1];
+ if (!strtol(start, &end, 10) || (end - start != exp->tok_len[*tok_idx - 1])) {
LOGVAL(ctx, NULL, LYVE_XPATH, "Invalid positional predicate \"%.*s\".", (int)exp->tok_len[*tok_idx - 1],
- exp->expr + exp->tok_pos[*tok_idx - 1]);
+ start);
goto token_error;
}
diff --git a/src/plugins.c b/src/plugins.c
index f4e10706d0..11c7d35085 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -638,6 +638,7 @@ lyplg_init(ly_bool builtin_type_plugins_only, ly_bool static_plugins_only)
ly_static_type_plugins_count = ly_plugins_types.count;
ly_static_ext_plugins_count = ly_plugins_extensions.count;
+ (void)static_plugins_only;
#ifndef STATIC
if (!static_plugins_only) {
/* external types */
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 9eb69b2026..7e1d4e30f9 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -151,6 +151,7 @@ ly_get_prefix(const struct lys_module *mod, LY_VALUE_FORMAT format, void *prefix
prefix = ly_xml_get_prefix(mod, prefix_data);
break;
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
prefix = ly_json_get_prefix(mod, prefix_data);
@@ -759,6 +760,7 @@ lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, uint32_t valu
break;
case LY_VALUE_CANON:
case LY_VALUE_LYB:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_STR_NS:
prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
@@ -936,7 +938,7 @@ lyplg_type_resolve_leafref_get_target_path(const struct lyxp_expr *path, const s
len = path->tok_pos[path->used - 3] + path->tok_len[path->used - 3];
/* generate the string path evaluated using hashes */
- quot = strchr(target_val, '\'') ? '\"' : '\'';
+ LY_CHECK_RET(ly_val_get_quot(ctx_node->module->ctx, target_val, "));
if (asprintf(&str_path, "%.*s[%s=%c%s%c]/%s", len, path->expr, path->expr + path->tok_pos[path->used - 1],
quot, target_val, quot, path->expr + path->tok_pos[path->used - 1]) == -1) {
LOGMEM(ctx_node->module->ctx);
@@ -949,7 +951,7 @@ lyplg_type_resolve_leafref_get_target_path(const struct lyxp_expr *path, const s
assert(p[LY_ARRAY_COUNT(p) - 1].node->nodetype & LYD_NODE_TERM);
/* generate the string path evaluated using hashes */
- quot = strchr(target_val, '\'') ? '\"' : '\'';
+ LY_CHECK_RET(ly_val_get_quot(ctx_node->module->ctx, target_val, "));
if (asprintf(&str_path, "%s[.=%c%s%c]", path->expr, quot, target_val, quot) == -1) {
LOGMEM(ctx_node->module->ctx);
rc = LY_EMEM;
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index 6610a4f6e3..8d16e87d19 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -59,18 +59,34 @@ instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, void *pr
switch (format) {
case LY_VALUE_XML:
- /* null the local module so that all the prefixes are printed */
+ case LY_VALUE_STR_NS:
+ /* zero the local module so that all the prefixes are printed */
mods = prefix_data;
local_mod = mods->objs[0];
mods->objs[0] = NULL;
+ break;
+ case LY_VALUE_SCHEMA:
+ case LY_VALUE_SCHEMA_RESOLVED:
+ /* nothing to do */
+ break;
+ case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
+ case LY_VALUE_JSON:
+ case LY_VALUE_LYB:
+ /* zero the local module so that the first node is always prefixed */
+ prefix_data = NULL;
+ break;
+ }
- /* fallthrough */
+ switch (format) {
+ case LY_VALUE_XML:
case LY_VALUE_SCHEMA:
case LY_VALUE_SCHEMA_RESOLVED:
/* everything is prefixed */
inherit_prefix = 0;
break;
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
case LY_VALUE_STR_NS:
@@ -104,10 +120,7 @@ instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, void *pr
LY_CHECK_GOTO(ret, cleanup);
/* default quote */
- quot = '\'';
- if (strchr(strval, quot)) {
- quot = '"';
- }
+ LY_CHECK_GOTO(ret = ly_val_get_quot(pred->key->module->ctx, strval, "), cleanup);
if (inherit_prefix) {
/* always the same prefix as the parent */
ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
@@ -123,10 +136,7 @@ instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, void *pr
LY_CHECK_GOTO(ret, cleanup);
/* default quote */
- quot = '\'';
- if (strchr(strval, quot)) {
- quot = '"';
- }
+ LY_CHECK_GOTO(ret = ly_val_get_quot(path[u].node->module->ctx, strval, "), cleanup);
ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
lydict_remove(path[u].node->module->ctx, strval);
break;
@@ -259,7 +269,11 @@ lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_v
{
char *ret;
- if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
+ switch (format) {
+ case LY_VALUE_CANON:
+ case LY_VALUE_JSON:
+ case LY_VALUE_LYB:
+ case LY_VALUE_CBOR:
if (dynamic) {
*dynamic = 0;
}
@@ -267,6 +281,8 @@ lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_v
*value_size_bits = strlen(value->_canonical) * 8;
}
return value->_canonical;
+ default:
+ break;
}
/* print the value in the specific format */
diff --git a/src/plugins_types/instanceid_keys.c b/src/plugins_types/instanceid_keys.c
index 6a129f93cf..f21f81c750 100644
--- a/src/plugins_types/instanceid_keys.c
+++ b/src/plugins_types/instanceid_keys.c
@@ -195,6 +195,7 @@ lyplg_type_store_instanceid_keys(const struct ly_ctx *ctx, const struct lysc_typ
switch (format) {
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
case LY_VALUE_STR_NS:
diff --git a/src/plugins_types/integer.c b/src/plugins_types/integer.c
index 99dd1e9492..9ddd676a8d 100644
--- a/src/plugins_types/integer.c
+++ b/src/plugins_types/integer.c
@@ -67,6 +67,11 @@ lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, con
if (format == LY_VALUE_LYB) {
/* copy the integer and correct the byte order */
+ if (value_size > sizeof num) {
+ ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid %s LYB value size %u B (max %zu B).",
+ lys_datatype2str(type->basetype), value_size, sizeof num);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
memcpy(&num, value, value_size);
num = le64toh(num);
} else {
@@ -314,6 +319,11 @@ lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, co
if (format == LY_VALUE_LYB) {
/* copy the integer and correct the byte order */
+ if (value_size > sizeof num) {
+ ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid %s LYB value size %u B (max %zu B).",
+ lys_datatype2str(type->basetype), value_size, sizeof num);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
memcpy(&num, value, value_size);
num = le64toh(num);
} else {
diff --git a/src/plugins_types/node_instanceid.c b/src/plugins_types/node_instanceid.c
index a94370f45f..18e05c84e1 100644
--- a/src/plugins_types/node_instanceid.c
+++ b/src/plugins_types/node_instanceid.c
@@ -63,18 +63,34 @@ node_instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, voi
switch (format) {
case LY_VALUE_XML:
- /* null the local module so that all the prefixes are printed */
+ case LY_VALUE_STR_NS:
+ /* zero the local module so that all the prefixes are printed */
mods = prefix_data;
local_mod = mods->objs[0];
mods->objs[0] = NULL;
+ break;
+ case LY_VALUE_SCHEMA:
+ case LY_VALUE_SCHEMA_RESOLVED:
+ /* nothing to do */
+ break;
+ case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
+ case LY_VALUE_JSON:
+ case LY_VALUE_LYB:
+ /* zero the local module so that the first node is always prefixed */
+ prefix_data = NULL;
+ break;
+ }
- /* fallthrough */
+ switch (format) {
+ case LY_VALUE_XML:
case LY_VALUE_SCHEMA:
case LY_VALUE_SCHEMA_RESOLVED:
/* everything is prefixed */
inherit_prefix = 0;
break;
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
case LY_VALUE_STR_NS:
@@ -108,10 +124,7 @@ node_instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, voi
LY_CHECK_GOTO(ret, cleanup);
/* default quote */
- quot = '\'';
- if (strchr(strval, quot)) {
- quot = '"';
- }
+ LY_CHECK_GOTO(ret = ly_val_get_quot(pred->key->module->ctx, strval, "), cleanup);
if (inherit_prefix) {
/* always the same prefix as the parent */
ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
@@ -127,10 +140,7 @@ node_instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, voi
LY_CHECK_GOTO(ret, cleanup);
/* default quote */
- quot = '\'';
- if (strchr(strval, quot)) {
- quot = '"';
- }
+ LY_CHECK_GOTO(ret = ly_val_get_quot(path[u].node->module->ctx, strval, "), cleanup);
ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
lydict_remove(path[u].node->module->ctx, strval);
break;
@@ -203,6 +213,7 @@ lyplg_type_store_node_instanceid(const struct ly_ctx *ctx, const struct lysc_typ
break;
case LY_VALUE_CANON:
case LY_VALUE_LYB:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_STR_NS:
prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
diff --git a/src/plugins_types/xpath1.0.c b/src/plugins_types/xpath1.0.c
index 18171e12fb..bb9cbe2651 100644
--- a/src/plugins_types/xpath1.0.c
+++ b/src/plugins_types/xpath1.0.c
@@ -222,11 +222,25 @@ lyplg_type_print_xpath10_value(const struct lyd_value_xpath10 *xp_val, LY_VALUE_
*str_value = NULL;
*err = NULL;
- if (format == LY_VALUE_XML) {
- /* null the local module so that all the prefixes are printed */
+ switch (format) {
+ case LY_VALUE_XML:
+ /* zero the local module so that all the prefixes are printed */
mods = prefix_data;
local_mod = mods->objs[0];
mods->objs[0] = NULL;
+ break;
+ case LY_VALUE_SCHEMA:
+ case LY_VALUE_SCHEMA_RESOLVED:
+ /* nothing to do */
+ break;
+ case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
+ case LY_VALUE_JSON:
+ case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
+ /* zero the local module so that the first node is always prefixed */
+ prefix_data = NULL;
+ break;
}
/* recursively print the expression */
@@ -249,7 +263,7 @@ lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type,
{
LY_ERR ret = LY_SUCCESS;
const struct ly_err_item *e;
- uint32_t value_size, temp_lo = LY_LOSTORE;
+ uint32_t value_size, *prev_lo, temp_lo = LY_LOSTORE;
struct lyd_value_xpath10 *val;
char *canon;
@@ -269,9 +283,9 @@ lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type,
LY_CHECK_GOTO(ret, cleanup);
/* parse */
- ly_temp_log_options(&temp_lo);
+ prev_lo = ly_temp_log_options(&temp_lo);
ret = lyxp_expr_parse(ctx, NULL, value_size ? value : "", value_size, 1, &val->exp);
- ly_temp_log_options(NULL);
+ ly_temp_log_options(prev_lo);
if (ret) {
/* get a copy of the error */
e = ly_err_last(ctx);
@@ -296,6 +310,7 @@ lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type,
switch (format) {
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
case LY_VALUE_STR_NS:
@@ -453,7 +468,7 @@ lyplg_type_print_xpath10(const struct ly_ctx *ctx, const struct lyd_value *value
/* LY_VALUE_STR_NS should never be transformed */
if ((val->format == LY_VALUE_STR_NS) || (format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) ||
- (format == LY_VALUE_LYB)) {
+ (format == LY_VALUE_LYB) || (format == LY_VALUE_CBOR)) {
/* canonical */
if (dynamic) {
*dynamic = 0;
diff --git a/src/printer_cbor.c b/src/printer_cbor.c
new file mode 100644
index 0000000000..49a1a3c314
--- /dev/null
+++ b/src/printer_cbor.c
@@ -0,0 +1,1385 @@
+/**
+ * @file printer_cbor.c
+ * @author Meher Rushi
+ * @brief CBOR printer for libyang data structure
+ *
+ * Copyright (c) 2026 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 _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+
+#include "compat.h"
+#include "context.h"
+#include "lcbor.h"
+#include "log.h"
+#include "ly_common.h"
+#include "out.h"
+#include "out_internal.h"
+#include "parser_data.h"
+#include "plugins_exts/metadata.h"
+#include "plugins_internal.h"
+#include "plugins_types.h"
+#include "printer_data.h"
+#include "printer_internal.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+
+/**
+ * @brief CBOR printer context.
+ */
+struct cborpr_ctx {
+ struct ly_out *out; /**< output specification */
+ const struct lyd_node *root; /**< root node of the subtree being printed */
+ const struct lyd_node *parent; /**< parent of the node being printed */
+ uint32_t options; /**< [Data printer flags](@ref dataprinterflags) */
+ const struct ly_ctx *ctx; /**< libyang context */
+
+ struct ly_set open; /**< currently open array(s) */
+ const struct lyd_node *first_leaflist; /**< first printed leaf-list instance, used when printing its metadata/attributes */
+
+ cbor_item_t *root_map; /**< root CBOR map */
+ cbor_item_t **arrays; /**< stack of currently open CBOR arrays, parallel to `open` (one per nesting level) */
+ uint32_t arrays_size; /**< allocated size of the `arrays` stack */
+};
+
+static LY_ERR cbor_print_node(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map);
+
+/**
+ * @brief Compare 2 nodes, despite it is regular data node or an opaq node, and
+ * decide if they corresponds to the same schema node.
+ *
+ * @return 1 - matching nodes, 0 - non-matching nodes
+ */
+static int
+matching_node(const struct lyd_node *node1, const struct lyd_node *node2)
+{
+ assert(node1 || node2);
+
+ if (!node1 || !node2) {
+ return 0;
+ } else if (node1->schema != node2->schema) {
+ return 0;
+ }
+ if (!node1->schema) {
+ /* compare node names */
+ struct lyd_node_opaq *onode1 = (struct lyd_node_opaq *)node1;
+ struct lyd_node_opaq *onode2 = (struct lyd_node_opaq *)node2;
+
+ if ((onode1->name.name != onode2->name.name) || (onode1->name.prefix != onode2->name.prefix)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Open a CBOR array for the specified @p node
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node First node of the array.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_array_open(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *array)
+{
+ LY_CHECK_RET(ly_set_add(&pctx->open, (void *)node, 0, NULL));
+
+ /* keep the array pointer on a stack parallel to `open` so that nested
+ * (leaf-)lists each have their own open array instead of a single shared one */
+ if (pctx->open.count > pctx->arrays_size) {
+ cbor_item_t **tmp = realloc(pctx->arrays, pctx->open.count * sizeof *pctx->arrays);
+
+ LY_CHECK_RET(!tmp, LY_EMEM);
+ pctx->arrays = tmp;
+ pctx->arrays_size = pctx->open.count;
+ }
+ pctx->arrays[pctx->open.count - 1] = array;
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Get the innermost currently open CBOR array.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @return The innermost open array, or NULL if none is open.
+ */
+static cbor_item_t *
+cbor_current_array(struct cborpr_ctx *pctx)
+{
+ if (!pctx->open.count) {
+ return NULL;
+ }
+ return pctx->arrays[pctx->open.count - 1];
+}
+
+/**
+ * @brief Get know if the array for the provided @p node is currently open.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to check.
+ * @return 1 in case the printer is currently in the array belonging to the provided @p node.
+ * @return 0 in case the provided @p node is not connected with the currently open array (or there is no open array).
+ */
+static int
+is_open_array(struct cborpr_ctx *pctx, const struct lyd_node *node)
+{
+ if (pctx->open.count && matching_node(node, pctx->open.dnodes[pctx->open.count - 1])) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * @brief Close the most inner CBOR array.
+ *
+ * @param[in] pctx CBOR printer context.
+ */
+static void
+cbor_print_array_close(struct cborpr_ctx *pctx)
+{
+ ly_set_rm_index(&pctx->open, pctx->open.count - 1, NULL);
+}
+
+/**
+ * @brief Get the node's module name to use as the @p node prefix in CBOR.
+ *
+ * @param[in] node Node to process.
+ * @return The name of the module where the @p node belongs, it can be NULL in case the module name
+ * cannot be determined (source format is XML and the refered namespace is unknown/not implemented in the current context).
+ */
+static const char *
+node_prefix(const struct lyd_node *node)
+{
+ if (node->schema) {
+ return node->schema->module->name;
+ } else {
+ struct lyd_node_opaq *onode = (struct lyd_node_opaq *)node;
+ const struct lys_module *mod;
+
+ switch (onode->format) {
+ case LY_VALUE_CBOR:
+ case LY_VALUE_JSON:
+ return onode->name.module_name;
+ case LY_VALUE_XML:
+ mod = ly_ctx_get_module_implemented_ns(onode->ctx, onode->name.module_ns);
+ if (!mod) {
+ return NULL;
+ }
+ return mod->name;
+ default:
+ /* cannot be created */
+ LOGINT(LYD_CTX(node));
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Compare 2 nodes if the belongs to the same module (if they come from the same namespace)
+ *
+ * Accepts both regulard a well as opaq nodes.
+ *
+ * @param[in] node1 The first node to compare.
+ * @param[in] node2 The second node to compare.
+ * @return 0 in case the nodes' modules are the same
+ * @return 1 in case the nodes belongs to different modules
+ */
+static int
+cbor_nscmp(const struct lyd_node *node1, const struct lyd_node *node2)
+{
+ assert(node1 || node2);
+
+ if (!node1 || !node2) {
+ return 1;
+ } else if (node1->schema && node2->schema) {
+ if (node1->schema->module == node2->schema->module) {
+ /* belongs to the same module */
+ return 0;
+ } else {
+ /* different modules */
+ return 1;
+ }
+ } else {
+ const char *pref1 = node_prefix(node1);
+ const char *pref2 = node_prefix(node2);
+
+ if ((pref1 && pref2) && (pref1 == pref2)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+}
+
+/**
+ * @brief Create CBOR member name as [prefix:]name
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node The data node being printed.
+ * @param[in] is_attr Flag if the metadata sign (@) is supposed to be added before the identifier.
+ * @return Newly allocated string with the member name, NULL on error.
+ */
+static char *
+cbor_print_member_name(struct cborpr_ctx *pctx, const struct lyd_node *node, ly_bool is_attr)
+{
+ char *name = NULL;
+ const char *prefix_str = node_prefix(node);
+ const char *node_name = node->schema->name;
+
+ if (cbor_nscmp(node, pctx->parent)) {
+ /* print "namespace" */
+ if (is_attr) {
+ if (asprintf(&name, "@%s:%s", prefix_str, node_name) == -1) {
+ return NULL;
+ }
+ } else {
+ if (asprintf(&name, "%s:%s", prefix_str, node_name) == -1) {
+ return NULL;
+ }
+ }
+ } else {
+ if (is_attr) {
+ if (asprintf(&name, "@%s", node_name) == -1) {
+ return NULL;
+ }
+ } else {
+ name = strdup(node_name);
+ }
+ }
+
+ return name;
+}
+
+/**
+ * @brief More generic alternative to cbor_print_member_name() to print some special cases of the member names.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] parent Parent node to compare modules deciding if the prefix is printed.
+ * @param[in] format Format to decide how to process the @p prefix.
+ * @param[in] name Name structure to provide name and prefix to print. If NULL, only "" name is printed.
+ * @param[in] is_attr Flag if the metadata sign (@) is supposed to be added before the identifier.
+ * @return Newly allocated string with the member name, NULL on error.
+ */
+static char *
+cbor_print_member_name2(struct cborpr_ctx *pctx, const struct lyd_node *parent, LY_VALUE_FORMAT format,
+ const struct ly_opaq_name *name, ly_bool is_attr)
+{
+ const char *module_name = NULL, *name_str;
+ char *result = NULL;
+
+ /* determine prefix string */
+ if (name) {
+ switch (format) {
+ case LY_VALUE_CBOR:
+ case LY_VALUE_JSON:
+ module_name = name->module_name;
+ break;
+ case LY_VALUE_XML: {
+ const struct lys_module *mod = NULL;
+
+ if (name->module_ns) {
+ mod = ly_ctx_get_module_implemented_ns(pctx->ctx, name->module_ns);
+ }
+ if (mod) {
+ module_name = mod->name;
+ }
+ break;
+ }
+ default:
+ /* cannot be created */
+ LOGINT(pctx->ctx);
+ return NULL;
+ }
+
+ name_str = name->name;
+ } else {
+ name_str = "";
+ }
+
+ /* create the member name */
+ if (module_name && (!parent || (node_prefix(parent) != module_name))) {
+ if (is_attr) {
+ if (asprintf(&result, "@%s:%s", module_name, name_str) == -1) {
+ return NULL;
+ }
+ } else {
+ if (asprintf(&result, "%s:%s", module_name, name_str) == -1) {
+ return NULL;
+ }
+ }
+ } else {
+ if (is_attr) {
+ if (asprintf(&result, "@%s", name_str) == -1) {
+ return NULL;
+ }
+ } else {
+ result = strdup(name_str);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * @brief Push into an array, check return value, and always decref the pushee.
+ *
+ * @param[in] ctx Context for logging.
+ * @param[in] array Array to push into.
+ * @param[in] pushee Item to push, is decrefd.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_array_push_check(const struct ly_ctx *ctx, cbor_item_t *array, cbor_item_t *pushee)
+{
+ LY_ERR rc = LY_SUCCESS;
+
+ if (!cbor_array_push(array, pushee)) {
+ LOGMEM(ctx);
+ rc = LY_EMEM;
+ }
+
+ cbor_decref(&pushee);
+ return rc;
+}
+
+/**
+ * @brief Print data value to CBOR item.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] ctx Context used to print the value.
+ * @param[in] val Data value to be printed.
+ * @param[in] local_mod Module of the current node.
+ * @param[out] item_p Pointer to store the created CBOR item.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_value(struct cborpr_ctx *pctx, const struct ly_ctx *ctx, const struct lyd_value *val,
+ const struct lys_module *local_mod, cbor_item_t **item_p)
+{
+ ly_bool dynamic;
+ LY_DATA_TYPE basetype;
+ const char *value;
+ cbor_item_t *item = NULL;
+
+ value = LYSC_GET_TYPE_PLG(val->realtype->plugin_ref)->print(ctx, val, LY_VALUE_CBOR, (void *)local_mod, &dynamic, NULL);
+ LY_CHECK_RET(!value, LY_EINVAL);
+ basetype = val->realtype->basetype;
+
+print_val:
+ /* leafref is not supported */
+ switch (basetype) {
+ case LY_TYPE_UNION:
+ /* use the resolved type */
+ val = &val->subvalue->value;
+ basetype = val->realtype->basetype;
+ goto print_val;
+
+ case LY_TYPE_BINARY:
+ case LY_TYPE_STRING:
+ case LY_TYPE_BITS:
+ case LY_TYPE_ENUM:
+ case LY_TYPE_INST:
+ case LY_TYPE_IDENT:
+ /* string types */
+ item = cbor_build_string(value);
+ break;
+
+ case LY_TYPE_INT64:
+ case LY_TYPE_UINT64:
+ case LY_TYPE_DEC64:
+ /* numeric types stored as strings in CBOR */
+ item = cbor_build_string(value);
+ break;
+
+ case LY_TYPE_INT8:
+ case LY_TYPE_INT16:
+ case LY_TYPE_INT32: {
+ /* signed integer types */
+ int64_t num = strtoll(value, NULL, 10);
+
+ if (num >= 0) {
+ item = cbor_build_uint64(num);
+ } else {
+ item = cbor_build_negint64(-num - 1);
+ }
+ break;
+ }
+
+ case LY_TYPE_UINT8:
+ case LY_TYPE_UINT16:
+ case LY_TYPE_UINT32: {
+ /* unsigned integer types */
+ uint64_t num = strtoull(value, NULL, 10);
+
+ item = cbor_build_uint64(num);
+ break;
+ }
+
+ case LY_TYPE_BOOL:
+ /* boolean */
+ if (strcmp(value, "true") == 0) {
+ item = cbor_build_bool(true);
+ } else {
+ item = cbor_build_bool(false);
+ }
+ break;
+
+ case LY_TYPE_EMPTY:
+ /* empty type is represented as [null] */
+ item = cbor_new_definite_array(1);
+ if (item) {
+ cbor_item_t *null_item = cbor_build_ctrl(CBOR_CTRL_NULL);
+
+ if (null_item) {
+ LY_CHECK_GOTO(cbor_array_push_check(pctx->ctx, item, null_item), cleanup);
+ }
+ }
+ break;
+
+ default:
+ /* error */
+ LOGINT(pctx->ctx);
+ goto cleanup;
+ }
+
+cleanup:
+ if (dynamic) {
+ free((char *)value);
+ }
+
+ *item_p = item;
+ return item ? LY_SUCCESS : LY_EMEM;
+}
+
+/**
+ * @brief Print all the attributes of the opaq node to CBOR map.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Opaq node where the attributes are placed.
+ * @param[in] attr_map CBOR map to add attributes to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_attribute(struct cborpr_ctx *pctx, const struct lyd_node_opaq *node, cbor_item_t *attr_map)
+{
+ struct lyd_attr *attr;
+ cbor_item_t *value_item = NULL;
+
+ for (attr = node->attr; attr; attr = attr->next) {
+ char *key = cbor_print_member_name2(pctx, &node->node, attr->format, &attr->name, 0);
+
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ if (attr->hints & (LYD_VALHINT_STRING | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM | LYD_VALHINT_NUM64)) {
+ value_item = cbor_build_string(attr->value);
+ } else if (attr->hints & (LYD_VALHINT_BOOLEAN | LYD_VALHINT_DECNUM)) {
+ if (strcmp(attr->value, "true") == 0) {
+ value_item = cbor_build_bool(true);
+ } else if (strcmp(attr->value, "false") == 0) {
+ value_item = cbor_build_bool(false);
+ } else {
+ /* numeric value as string */
+ value_item = cbor_build_string(attr->value);
+ }
+ } else if (attr->hints & LYD_VALHINT_EMPTY) {
+ value_item = cbor_new_definite_array(1);
+ if (value_item) {
+ cbor_item_t *null_item = cbor_build_ctrl(CBOR_CTRL_NULL);
+
+ if (null_item) {
+ if (cbor_array_push_check(pctx->ctx, value_item, null_item)) {
+ cbor_decref(&value_item);
+ return LY_EMEM;
+ }
+ }
+ }
+ } else {
+ /* unknown value format with no hints, use universal string */
+ value_item = cbor_build_string(attr->value);
+ }
+
+ if (!value_item) {
+ free(key);
+ return LY_EMEM;
+ }
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(value_item)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(attr_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print all the metadata of the node to CBOR map.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Node where the metadata are placed.
+ * @param[in] wdmod With-defaults module to mark that default attribute is supposed to be printed.
+ * @param[in] meta_map CBOR map to add metadata to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_metadata(struct cborpr_ctx *pctx, const struct lyd_node *node, const struct lys_module *wdmod,
+ cbor_item_t *meta_map)
+{
+ struct lyd_meta *meta;
+ cbor_item_t *value_item = NULL;
+ char *key = NULL;
+
+ if (wdmod) {
+ if (asprintf(&key, "%s:default", wdmod->name) == -1) {
+ return LY_EMEM;
+ }
+ value_item = cbor_build_bool(true);
+ if (!value_item) {
+ free(key);
+ return LY_EMEM;
+ }
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(value_item)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(meta_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+
+ for (meta = node->meta; meta; meta = meta->next) {
+ if (!lyd_metadata_should_print(meta)) {
+ continue;
+ }
+
+ if (asprintf(&key, "%s:%s", meta->annotation->module->name, meta->name) == -1) {
+ return LY_EMEM;
+ }
+
+ LY_CHECK_RET(cbor_print_value(pctx, LYD_CTX(node), &meta->value, NULL, &value_item));
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(value_item)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(meta_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Check if a value can be printed for at least one metadata.
+ *
+ * @param[in] node Node to check.
+ * @return 1 if node has printable meta otherwise 0.
+ */
+static ly_bool
+node_has_printable_meta(const struct lyd_node *node)
+{
+ struct lyd_meta *iter;
+
+ if (!node->meta) {
+ return 0;
+ }
+
+ LY_LIST_FOR(node->meta, iter) {
+ if (lyd_metadata_should_print(iter)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Print attributes/metadata of the given @p node to CBOR map.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node where the attributes/metadata are placed.
+ * @param[in] parent_map CBOR map to add the metadata to.
+ * @param[in] inner Flag if the @p node is an inner node in the tree.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_attributes(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map, ly_bool inner)
+{
+ const struct lys_module *wdmod = NULL;
+ cbor_item_t *meta_map = NULL;
+ char *key = NULL;
+
+ if (node->schema && (node->schema->nodetype != LYS_CONTAINER) && (((node->flags & LYD_DEFAULT) &&
+ (pctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG))) ||
+ ((pctx->options & LYD_PRINT_WD_ALL_TAG) && lyd_is_default(node)))) {
+ /* we have implicit OR explicit default node */
+ /* get with-defaults module */
+ wdmod = ly_ctx_get_module_implemented(LYD_CTX(node), "ietf-netconf-with-defaults");
+ }
+
+ if (node->schema && (wdmod || node_has_printable_meta(node))) {
+ meta_map = cbor_new_indefinite_map();
+ LY_CHECK_RET(!meta_map, LY_EMEM);
+
+ LY_CHECK_RET(cbor_print_metadata(pctx, node, wdmod, meta_map));
+
+ if (inner) {
+ key = cbor_print_member_name2(pctx, lyd_parent(node), LY_VALUE_JSON, NULL, 1);
+ } else {
+ key = cbor_print_member_name(pctx, node, 1);
+ }
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(meta_map)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ } else if (!node->schema && ((struct lyd_node_opaq *)node)->attr) {
+ meta_map = cbor_new_indefinite_map();
+ LY_CHECK_RET(!meta_map, LY_EMEM);
+
+ LY_CHECK_RET(cbor_print_attribute(pctx, (struct lyd_node_opaq *)node, meta_map));
+
+ if (inner) {
+ key = cbor_print_member_name2(pctx, lyd_parent(node), LY_VALUE_JSON, NULL, 1);
+ } else {
+ key = cbor_print_member_name2(pctx, lyd_parent(node), ((struct lyd_node_opaq *)node)->format,
+ &((struct lyd_node_opaq *)node)->name, 1);
+ }
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(meta_map)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print leaf data node including its metadata.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to print.
+ * @param[in] parent_map CBOR map to add the leaf to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_leaf(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map)
+{
+ char *key = NULL;
+ cbor_item_t *value_item = NULL;
+
+ key = cbor_print_member_name(pctx, node, 0);
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ LY_CHECK_ERR_RET(cbor_print_value(pctx, LYD_CTX(node), &((const struct lyd_node_term *)node)->value,
+ node->schema->module, &value_item), free(key), LY_EINVAL);
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(value_item)
+ };
+
+ if (!cbor_map_add(parent_map, pair)) {
+ free(key);
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ free(key);
+
+ /* print attributes as sibling */
+ cbor_print_attributes(pctx, node, parent_map, 0);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print anydata/anyxml content to CBOR item.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] any Anydata node to print.
+ * @param[out] item_p Pointer to store the created CBOR item.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_any_content(struct cborpr_ctx *pctx, struct lyd_node_any *any, cbor_item_t **item_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_node *iter;
+ const struct lyd_node *prev_parent;
+ uint32_t prev_opts;
+ cbor_item_t *content_map = NULL;
+
+ assert(any->schema->nodetype & LYD_NODE_ANY);
+
+ if ((any->schema->nodetype == LYS_ANYDATA) && any->value) {
+ LOGINT_RET(pctx->ctx);
+ }
+
+ if (any->child) {
+ /* create a map for the content */
+ content_map = cbor_new_indefinite_map();
+ LY_CHECK_RET(!content_map, LY_EMEM);
+
+ /* print data tree */
+ prev_parent = pctx->parent;
+ prev_opts = pctx->options;
+ pctx->parent = &any->node;
+ pctx->options &= ~LYD_PRINT_SIBLINGS;
+ LY_LIST_FOR(any->child, iter) {
+ ret = cbor_print_node(pctx, iter, content_map);
+ LY_CHECK_ERR_RET(ret, cbor_decref(&content_map), ret);
+ }
+ pctx->parent = prev_parent;
+ pctx->options = prev_opts;
+
+ *item_p = content_map;
+ } else if (any->value) {
+ /* print as a string */
+ *item_p = cbor_build_string(any->value);
+ } else {
+ /* no content */
+ if (any->schema->nodetype == LYS_ANYXML) {
+ *item_p = cbor_build_ctrl(CBOR_CTRL_NULL);
+ } else {
+ *item_p = cbor_new_indefinite_map();
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print content of a single container/list data node including its metadata.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to print.
+ * @param[out] item_p Pointer to store the created CBOR map.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_inner(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t **item_p)
+{
+ struct lyd_node *child;
+ const struct lyd_node *prev_parent;
+ cbor_item_t *inner_map = NULL;
+
+ /* create map for inner node */
+ inner_map = cbor_new_indefinite_map();
+ LY_CHECK_RET(!inner_map, LY_EMEM);
+
+ /* print attributes first */
+ cbor_print_attributes(pctx, node, inner_map, 1);
+
+ /* print children */
+ prev_parent = pctx->parent;
+ pctx->parent = node;
+ LY_LIST_FOR(lyd_child(node), child) {
+ LY_CHECK_ERR_RET(cbor_print_node(pctx, child, inner_map), cbor_decref(&inner_map), LY_EINVAL);
+ }
+ pctx->parent = prev_parent;
+
+ *item_p = inner_map;
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print container data node including its metadata.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to print.
+ * @param[in] parent_map CBOR map to add the container to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_container(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map)
+{
+ char *key = NULL;
+ cbor_item_t *inner_map = NULL;
+
+ key = cbor_print_member_name(pctx, node, 0);
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ LY_CHECK_ERR_RET(cbor_print_inner(pctx, node, &inner_map), free(key), LY_EINVAL);
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(inner_map)
+ };
+
+ if (!cbor_map_add(parent_map, pair)) {
+ free(key);
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ free(key);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print anydata/anyxml data node including its metadata.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to print.
+ * @param[in] parent_map CBOR map to add the anydata to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_any(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map)
+{
+ char *key = NULL;
+ cbor_item_t *any_item = NULL;
+
+ key = cbor_print_member_name(pctx, node, 0);
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ LY_CHECK_ERR_RET(cbor_print_any_content(pctx, (struct lyd_node_any *)node, &any_item), free(key), LY_EINVAL);
+
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(any_item)
+ };
+
+ if (!cbor_map_add(parent_map, pair)) {
+ free(key);
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ free(key);
+
+ /* print attributes as sibling */
+ cbor_print_attributes(pctx, node, parent_map, 0);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Check whether a node is the last printed instance of a (leaf-)list.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Last printed node.
+ * @return Whether it is the last printed instance or not.
+ */
+static ly_bool
+cbor_print_array_is_last_inst(struct cborpr_ctx *pctx, const struct lyd_node *node)
+{
+ if (!is_open_array(pctx, node)) {
+ /* no array open */
+ return 0;
+ }
+
+ if ((pctx->root == node) && !(pctx->options & LYD_PRINT_SIBLINGS)) {
+ /* the only printed instance */
+ return 1;
+ }
+
+ if (!node->next || (node->next->schema != node->schema)) {
+ /* last instance */
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Print single leaf-list or list instance.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to print.
+ * @param[in] parent_map CBOR map to add the node to.
+ * @param[in,out] array_p Pointer to the array being built.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_leaf_list(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map)
+{
+ const struct lys_module *wdmod = NULL;
+ cbor_item_t *value_item = NULL;
+ cbor_item_t *inner_map = NULL;
+ cbor_item_t *array;
+ char *key = NULL;
+
+ if (!is_open_array(pctx, node)) {
+ /* start new array */
+ cbor_item_t *new_array = cbor_new_indefinite_array();
+
+ LY_CHECK_RET(!new_array, LY_EMEM);
+ LY_CHECK_ERR_RET(cbor_print_array_open(pctx, node, new_array), cbor_decref(&new_array), LY_EINVAL);
+ }
+ /* the array for this (leaf-)list is the innermost open one */
+ array = cbor_current_array(pctx);
+
+ if (node->schema->nodetype == LYS_LIST) {
+ /* print list's content */
+ LY_CHECK_RET(cbor_print_inner(pctx, node, &inner_map));
+ /* re-read: nested (leaf-)lists may have pushed/popped their own arrays */
+ LY_CHECK_RET(cbor_array_push_check(pctx->ctx, cbor_current_array(pctx), inner_map));
+ } else {
+ assert(node->schema->nodetype == LYS_LEAFLIST);
+
+ LY_CHECK_RET(cbor_print_value(pctx, LYD_CTX(node), &((const struct lyd_node_term *)node)->value,
+ node->schema->module, &value_item));
+ LY_CHECK_RET(cbor_array_push_check(pctx->ctx, array, value_item));
+
+ if (!pctx->first_leaflist) {
+ if (((node->flags & LYD_DEFAULT) && (pctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG))) ||
+ ((pctx->options & LYD_PRINT_WD_ALL_TAG) && lyd_is_default(node))) {
+ /* we have implicit OR explicit default node, get with-defaults module */
+ wdmod = ly_ctx_get_module_implemented(LYD_CTX(node), "ietf-netconf-with-defaults");
+ }
+ if (wdmod || node_has_printable_meta(node)) {
+ /* we will be printing metadata for these siblings */
+ pctx->first_leaflist = node;
+ }
+ }
+ }
+
+ if (cbor_print_array_is_last_inst(pctx, node)) {
+ array = cbor_current_array(pctx);
+ key = cbor_print_member_name(pctx, node, 0);
+ /* add completed array to parent map */
+ if (key) {
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(array)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ } else {
+ cbor_decref(&array);
+ cbor_print_array_close(pctx);
+ return LY_EMEM;
+ }
+ cbor_print_array_close(pctx);
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print leaf-list's metadata or opaque nodes attributes.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] parent_map CBOR map to add metadata to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_meta_attr_leaflist(struct cborpr_ctx *pctx, cbor_item_t *parent_map)
+{
+ const struct lyd_node *prev, *node, *iter;
+ const struct lys_module *wdmod = NULL, *iter_wdmod;
+ const struct lyd_node_opaq *opaq = NULL;
+ cbor_item_t *meta_array = NULL;
+ cbor_item_t *meta_map = NULL;
+ char *key = NULL;
+
+ assert(pctx->first_leaflist);
+
+ if (pctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG)) {
+ /* get with-defaults module */
+ wdmod = ly_ctx_get_module_implemented(pctx->ctx, "ietf-netconf-with-defaults");
+ }
+
+ /* node is the first instance of the leaf-list */
+ for (node = pctx->first_leaflist, prev = pctx->first_leaflist->prev;
+ prev->next && matching_node(node, prev);
+ node = prev, prev = node->prev) {}
+
+ /* create metadata array */
+ meta_array = cbor_new_indefinite_array();
+ LY_CHECK_RET(!meta_array, LY_EMEM);
+
+ if (node->schema) {
+ key = cbor_print_member_name(pctx, node, 1);
+ } else {
+ opaq = (struct lyd_node_opaq *)node;
+ key = cbor_print_member_name2(pctx, lyd_parent(node), opaq->format, &opaq->name, 1);
+ }
+ LY_CHECK_ERR_RET(!key, cbor_decref(&meta_array), LY_EMEM);
+
+ LY_LIST_FOR(node, iter) {
+ if (iter->schema && ((iter->flags & LYD_DEFAULT) || ((pctx->options & LYD_PRINT_WD_ALL_TAG) && lyd_is_default(iter)))) {
+ iter_wdmod = wdmod;
+ } else {
+ iter_wdmod = NULL;
+ }
+
+ if ((iter->schema && (node_has_printable_meta(iter) || iter_wdmod)) || (opaq && opaq->attr)) {
+ meta_map = cbor_new_indefinite_map();
+ if (!meta_map) {
+ free(key);
+ cbor_decref(&meta_array);
+ return LY_EMEM;
+ }
+
+ if (iter->schema) {
+ LY_CHECK_ERR_RET(cbor_print_metadata(pctx, iter, iter_wdmod, meta_map),
+ free(key); cbor_decref(&meta_array); cbor_decref(&meta_map), LY_EINVAL);
+ } else {
+ LY_CHECK_ERR_RET(cbor_print_attribute(pctx, (struct lyd_node_opaq *)iter, meta_map),
+ free(key); cbor_decref(&meta_array); cbor_decref(&meta_map), LY_EINVAL);
+ }
+
+ LY_CHECK_RET(cbor_array_push_check(pctx->ctx, meta_array, meta_map));
+ } else {
+ cbor_item_t *null_item = cbor_build_ctrl(CBOR_CTRL_NULL);
+
+ LY_CHECK_RET(cbor_array_push_check(pctx->ctx, meta_array, null_item));
+ }
+
+ if (!matching_node(iter, iter->next)) {
+ break;
+ }
+ }
+
+ /* add metadata array to parent map */
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(meta_array)
+ };
+
+ free(key);
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print opaq data node including its attributes.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Opaq node to print.
+ * @param[in] parent_map CBOR map to add the node to.
+ * @param[in,out] array_p Pointer to the array being built (for leaf-lists/lists).
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_opaq(struct cborpr_ctx *pctx, const struct lyd_node_opaq *node, cbor_item_t *parent_map)
+{
+ ly_bool first = 1, last = 1;
+ uint32_t hints;
+ char *key = NULL;
+ cbor_item_t *value_item = NULL;
+
+ if (node->hints == LYD_HINT_DATA) {
+ /* useless and confusing hints */
+ hints = 0;
+ } else {
+ hints = node->hints;
+ }
+
+ if (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
+ if (node->prev->next && matching_node(node->prev, &node->node)) {
+ first = 0;
+ }
+ if (node->next && matching_node(&node->node, node->next)) {
+ last = 0;
+ }
+ }
+
+ if (first) {
+ key = cbor_print_member_name2(pctx, pctx->parent, node->format, &node->name, 0);
+ LY_CHECK_RET(!key, LY_EMEM);
+
+ if (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
+ cbor_item_t *new_array = cbor_new_indefinite_array();
+
+ LY_CHECK_ERR_RET(!new_array, free(key), LY_EMEM);
+ LY_CHECK_ERR_RET(cbor_print_array_open(pctx, &node->node, new_array),
+ cbor_decref(&new_array); free(key), LY_EINVAL);
+ }
+ }
+
+ if (node->child || (hints & LYD_NODEHINT_LIST) || (hints & LYD_NODEHINT_CONTAINER)) {
+ cbor_item_t *inner_map = NULL;
+
+ LY_CHECK_ERR_RET(cbor_print_inner(pctx, &node->node, &inner_map), free(key), LY_EINVAL);
+
+ if (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
+ LY_CHECK_RET(cbor_array_push_check(pctx->ctx, cbor_current_array(pctx), inner_map));
+ } else {
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(inner_map)
+ };
+
+ free(key);
+ key = NULL;
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+ } else {
+ if (hints & LYD_VALHINT_EMPTY) {
+ value_item = cbor_new_definite_array(1);
+ if (value_item) {
+ cbor_item_t *null_item = cbor_build_ctrl(CBOR_CTRL_NULL);
+
+ if (null_item) {
+ if (cbor_array_push_check(pctx->ctx, value_item, null_item)) {
+ cbor_decref(&value_item);
+ return LY_EMEM;
+ }
+ }
+ }
+ } else if ((hints & (LYD_VALHINT_BOOLEAN | LYD_VALHINT_DECNUM)) && !(hints & LYD_VALHINT_NUM64)) {
+ if (strcmp(node->value, "true") == 0) {
+ value_item = cbor_build_bool(true);
+ } else if (strcmp(node->value, "false") == 0) {
+ value_item = cbor_build_bool(false);
+ } else {
+ value_item = cbor_build_string(node->value);
+ }
+ } else {
+ /* string or a large number */
+ value_item = cbor_build_string(node->value);
+ }
+
+ LY_CHECK_ERR_RET(!value_item, free(key), LY_EMEM);
+
+ if (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
+ LY_CHECK_RET(cbor_array_push_check(pctx->ctx, cbor_current_array(pctx), value_item));
+ } else {
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(value_item)
+ };
+
+ free(key);
+ key = NULL;
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+
+ if (!(hints & LYD_NODEHINT_LEAFLIST)) {
+ /* attributes */
+ cbor_print_attributes(pctx, (const struct lyd_node *)node, parent_map, 0);
+ } else if (!pctx->first_leaflist && node->attr) {
+ /* attributes printed later */
+ pctx->first_leaflist = &node->node;
+ }
+ }
+
+ if (last && (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST))) {
+ if (key) {
+ struct cbor_pair pair = {
+ .key = cbor_move(cbor_build_string(key)),
+ .value = cbor_move(cbor_current_array(pctx))
+ };
+
+ free(key);
+
+ if (!cbor_map_add(parent_map, pair)) {
+ cbor_decref(&pair.key);
+ cbor_decref(&pair.value);
+ return LY_EMEM;
+ }
+ }
+ cbor_print_array_close(pctx);
+ }
+
+ if (key) {
+ free(key);
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print all the types of data node including its metadata.
+ *
+ * @param[in] pctx CBOR printer context.
+ * @param[in] node Data node to print.
+ * @param[in] parent_map CBOR map to add the node to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+cbor_print_node(struct cborpr_ctx *pctx, const struct lyd_node *node, cbor_item_t *parent_map)
+{
+
+ if (!lyd_node_should_print(node, pctx->options)) {
+ if (cbor_print_array_is_last_inst(pctx, node)) {
+ cbor_print_array_close(pctx);
+ }
+ return LY_SUCCESS;
+ }
+
+ if (!node->schema) {
+ LY_CHECK_RET(cbor_print_opaq(pctx, (const struct lyd_node_opaq *)node, parent_map));
+ } else {
+ switch (node->schema->nodetype) {
+ case LYS_RPC:
+ case LYS_ACTION:
+ case LYS_NOTIF:
+ case LYS_CONTAINER:
+ LY_CHECK_RET(cbor_print_container(pctx, node, parent_map));
+ break;
+ case LYS_LEAF:
+ LY_CHECK_RET(cbor_print_leaf(pctx, node, parent_map));
+ break;
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ LY_CHECK_RET(cbor_print_leaf_list(pctx, node, parent_map));
+ break;
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ LY_CHECK_RET(cbor_print_any(pctx, node, parent_map));
+ break;
+ default:
+ LOGINT(pctx->ctx);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (pctx->first_leaflist && !matching_node(node->next, pctx->first_leaflist)) {
+ cbor_print_meta_attr_leaflist(pctx, parent_map);
+ pctx->first_leaflist = NULL;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+cbor_print_data(struct ly_out *out, const struct lyd_node *root, uint32_t options)
+{
+ const struct lyd_node *node;
+ struct cborpr_ctx pctx = {0};
+ unsigned char *buffer = NULL;
+ size_t buffer_size = 0;
+
+ if (!root) {
+ /* empty data - print empty map */
+ cbor_item_t *empty_map = cbor_new_indefinite_map();
+
+ LY_CHECK_RET(!empty_map, LY_EMEM);
+
+ buffer_size = cbor_serialize_alloc(empty_map, &buffer, &buffer_size);
+ cbor_decref(&empty_map);
+
+ if (buffer_size == 0) {
+ return LY_EMEM;
+ }
+
+ ly_write_(out, (const char *)buffer, buffer_size);
+ free(buffer);
+ ly_print_flush(out);
+ return LY_SUCCESS;
+ }
+
+ pctx.out = out;
+ pctx.parent = NULL;
+ pctx.options = options;
+ pctx.ctx = LYD_CTX(root);
+
+ /* create root map */
+ pctx.root_map = cbor_new_indefinite_map();
+ LY_CHECK_RET(!pctx.root_map, LY_EMEM);
+
+ /* print content */
+ LY_LIST_FOR(root, node) {
+ pctx.root = node;
+ LY_CHECK_ERR_RET(cbor_print_node(&pctx, node, pctx.root_map),
+ cbor_decref(&pctx.root_map); ly_set_erase(&pctx.open, NULL); free(pctx.arrays), LY_EINVAL);
+ if (!(options & LYD_PRINT_SIBLINGS)) {
+ break;
+ }
+ }
+
+ /* serialize CBOR to buffer */
+ buffer_size = cbor_serialize_alloc(pctx.root_map, &buffer, &buffer_size);
+ cbor_decref(&pctx.root_map);
+
+ if (buffer_size == 0) {
+ ly_set_erase(&pctx.open, NULL);
+ free(pctx.arrays);
+ return LY_EMEM;
+ }
+
+ /* write to output */
+ ly_write_(out, (const char *)buffer, buffer_size);
+ free(buffer);
+
+ assert(!pctx.open.count);
+ ly_set_erase(&pctx.open, NULL);
+ free(pctx.arrays);
+
+ ly_print_flush(out);
+ return LY_SUCCESS;
+}
diff --git a/src/printer_context.c b/src/printer_context.c
index 2b5871c991..f24022f4f3 100644
--- a/src/printer_context.c
+++ b/src/printer_context.c
@@ -1043,6 +1043,7 @@ ctxp_pattern(const struct lysc_pattern *orig_pattern, struct lysc_pattern **patt
}
p->inverted = orig_pattern->inverted;
+ p->format = orig_pattern->format;
p->refcount = orig_pattern->refcount;
/* shared */
diff --git a/src/printer_data.c b/src/printer_data.c
index 174131b073..ebd162e7e1 100644
--- a/src/printer_data.c
+++ b/src/printer_data.c
@@ -38,6 +38,16 @@ lyd_print_(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, u
case LYD_LYB:
ret = lyb_print_data(out, root, options);
break;
+#ifdef ENABLE_CBOR_SUPPORT
+ case LYD_CBOR:
+ ret = cbor_print_data(out, root, options);
+ break;
+#else
+ case LYD_CBOR:
+ LOGERR(root ? LYD_CTX(root) : NULL, LY_ENOT, "CBOR format not supported, libcbor not found.");
+ ret = LY_ENOT;
+ break;
+#endif /* ENABLE_CBOR_SUPPORT */
case LYD_UNKNOWN:
LOGERR(root ? LYD_CTX(root) : NULL, LY_EINVAL, "Unknown data output format.");
ret = LY_EINVAL;
diff --git a/src/printer_internal.h b/src/printer_internal.h
index 5cf205e77b..0f1d8b827a 100644
--- a/src/printer_internal.h
+++ b/src/printer_internal.h
@@ -185,4 +185,14 @@ LY_ERR json_print_data(struct ly_out *out, const struct lyd_node *root, uint32_t
*/
LY_ERR lyb_print_data(struct ly_out *out, const struct lyd_node *root, uint32_t options);
+/**
+ * @brief CBOR printer of YANG data.
+ *
+ * @param[in] out Output structure.
+ * @param[in] root The root element of the (sub)tree to print.
+ * @param[in] options [Data printer flags](@ref dataprinterflags).
+ * @return LY_ERR value, number of the printed bytes is updated in ::ly_out.printed.
+ */
+LY_ERR cbor_print_data(struct ly_out *out, const struct lyd_node *root, uint32_t options);
+
#endif /* LY_PRINTER_INTERNAL_H_ */
diff --git a/src/printer_json.c b/src/printer_json.c
index 25f00c51f8..f590a81d46 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -170,6 +170,7 @@ node_prefix(const struct lyd_node *node, const struct lysc_node *snode, const ch
onode = (struct lyd_node_opaq *)node;
switch (onode->format) {
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
*mod_name = onode->name.module_name;
if (data_dict) {
@@ -342,6 +343,7 @@ json_print_member2(struct jsonpr_ctx *pctx, const struct lyd_node *parent, LY_VA
/* determine prefix string */
if (name) {
switch (format) {
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
module_name = name->module_name;
break;
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index cb6d1621af..25f1caf169 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -60,12 +60,14 @@ lyb_print_ctx_free(struct lyd_ctx *lydctx)
lyd_ctx_free(lydctx);
- LY_ARRAY_FOR(ctx->print_ctx->sib_hts, u) {
- lyht_free(ctx->print_ctx->sib_hts[u].ht, NULL);
+ if (ctx->print_ctx) {
+ LY_ARRAY_FOR(ctx->print_ctx->sib_hts, u) {
+ lyht_free(ctx->print_ctx->sib_hts[u].ht, NULL);
+ }
+ LY_ARRAY_FREE(ctx->print_ctx->sib_hts);
+ free(ctx->print_ctx);
}
- LY_ARRAY_FREE(ctx->print_ctx->sib_hts);
- free(ctx->print_ctx);
free(ctx);
}
@@ -753,6 +755,7 @@ lyb_print_prefix_data(LY_VALUE_FORMAT format, const void *prefix_data, struct ly
LY_CHECK_RET(lyb_write_string(ns->uri, 0, lybctx));
}
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
/* nothing to print */
diff --git a/src/printer_sid.c b/src/printer_sid.c
new file mode 100644
index 0000000000..a8eff1db36
--- /dev/null
+++ b/src/printer_sid.c
@@ -0,0 +1,989 @@
+/**
+ * @file printer_sid.c
+ * @author Petr Hanzlik
+ * @brief Generation and update of .sid files (RFC 9595).
+ *
+ * Copyright (c) 2026 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/BSD-3-Clause
+ */
+
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include "compat.h"
+#include "context.h"
+#include "log.h"
+#include "ly_common.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+#include "tree_schema_internal.h"
+#include "version.h"
+
+/**
+ * @brief Internal representation of a single SID item before it is written
+ * into the ietf-sid-file data tree.
+ *
+ * Ownership of the strings depends on the producer and must be respected by every cleanup path; the type itself does not express it.
+ */
+struct sid_item {
+ char *ns; /**< Namespace string: "module", "identity", "feature", or "data". */
+ char *ident; /**< Identifier: module/submodule name, identity/feature name, or absolute schema-node path. */
+ uint64_t sid; /**< SID assigned to the item (0 until assigned). */
+ char *status; /**< Item status: "unstable"/"obsolete", or NULL. */
+};
+
+/**
+ * @brief Collection state for gathering SID items, also passed as data to the DFS callback collecting "data" namespace items.
+ */
+struct sid_collect_data {
+ struct sid_item *items; /**< Items array being filled. */
+ uint64_t count; /**< Number of items collected so far; exceeding @p max, surplus items are only counted. */
+ uint64_t max; /**< Maximum number of items (capacity of the array). */
+ struct ly_ctx *ctx; /**< libyang context used for error logging. */
+ const struct lys_module *module; /**< Module whose nodes are collected; used to attribute augmented nodes to their defining module. */
+};
+
+/**
+ * @brief Assignment range of an .sid file.
+ */
+struct sid_range {
+ uint64_t entry_point; /**< First SID of the range. */
+ uint64_t size; /**< Number of SIDs in the range. */
+};
+
+/**
+ * @brief Comparator for qsort that sorts SID items.
+ *
+ * Sort order alphabetical:
+ * 1. Namespace descending.
+ * 2. Identifier ascending.
+ *
+ * @param[in] a First item (struct sid_item *).
+ * @param[in] b Second item (struct sid_item *).
+ * @return <0 if @p a comes before @p b, 0 if equal, >0 if @p a comes after @p b.
+ */
+static int
+compare_sid(const void *a, const void *b)
+{
+ const struct sid_item *item_a = a, *item_b = b;
+ char ns_a, ns_b;
+
+ ns_a = item_a->ns[0];
+ ns_b = item_b->ns[0];
+
+ if (ns_a == ns_b) {
+ return strcmp(item_a->ident, item_b->ident);
+ }
+
+ return ns_b - ns_a;
+}
+
+/**
+ * @brief Add one collected item to the collection array.
+ *
+ * @param[in,out] collect Collection state (items/count/max, ctx used for error logging).
+ * @param[in] ns Namespace string: "module", "identity", "feature", or "data".
+ * @param[in] name Identifier string to duplicate into the item.
+ * @return LY_SUCCESS on success (also if the capacity is exceeded, the item is then only counted and the caller reports the overflow after full collection).
+ * @return LY_EMEM on memory allocation failure.
+ */
+static LY_ERR
+sid_item_add(struct sid_collect_data *collect, const char *ns, const char *name)
+{
+ /* overflow is only counted here; the exact number of excess items is
+ * reported by the caller after the whole schema has been collected */
+ if (collect->count >= collect->max) {
+ collect->count++;
+ return LY_SUCCESS;
+ }
+
+ collect->items[collect->count].ns = (char *)ns;
+ collect->items[collect->count].ident = strdup(name);
+ LY_CHECK_ERR_RET(!collect->items[collect->count].ident, LOGMEM(collect->ctx), LY_EMEM);
+
+ collect->count++;
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Build the schema-node-path identifier of a compiled node as required by RFC 9595:
+ * like ::lysc_path with ::LYSC_PATH_LOG, but choice and case node names are omitted
+ * (they never get a SID and never appear in identifiers), while input and output are kept.
+ *
+ * @param[in] node Node to build the identifier for.
+ * @return Newly allocated path, the caller frees it.
+ * @return NULL on memory allocation failure.
+ */
+static char *
+sid_node_path(const struct lysc_node *node)
+{
+ const struct lysc_node *iter, *par;
+ char *path = NULL;
+ int len = 0;
+
+ for (iter = node; iter && (len >= 0); iter = iter->parent) {
+ char *s;
+
+ if (iter->nodetype & (LYS_CHOICE | LYS_CASE)) {
+ /* never part of a SID identifier, but children must be reached */
+ continue;
+ }
+
+ /* nearest non-choice/case ancestor, for the module prefix decision */
+ for (par = iter->parent; par && (par->nodetype & (LYS_CHOICE | LYS_CASE)); par = par->parent) {}
+
+ s = path;
+ if (!par || (par->module != iter->module)) {
+ /* module prefix (top-level node or module change through an augment) */
+ len = asprintf(&path, "/%s:%s%s", iter->module->name, iter->name, s ? s : "");
+ } else {
+ len = asprintf(&path, "/%s%s", iter->name, s ? s : "");
+ }
+ free(s);
+ }
+
+ if (len < 0) {
+ free(path);
+ return NULL;
+ }
+ return path;
+}
+
+/**
+ * @brief DFS callback for ::lysc_module_dfs_full that collects each schema node as a "data" namespace item.
+ *
+ * @param[in] node Current schema node.
+ * @param[in,out] data Pointer to ::sid_collect_data.
+ * @param[out] dfs_continue Unused, the whole tree is always traversed.
+ * @return LY_SUCCESS on success.
+ * @return LY_EMEM on allocation failure.
+ */
+static LY_ERR
+collect_data_cb(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue))
+{
+ struct sid_collect_data *collect_data = data;
+ LY_ERR rc;
+ char *path;
+
+ if (node->nodetype & (LYS_CHOICE | LYS_CASE)) {
+ return LY_SUCCESS; /* choice/case get no item, but their subtree is still traversed */
+ }
+
+ /* collect only nodes defined by the module being processed; when another
+ * module's tree is traversed this keeps exactly the nodes augmented in by
+ * the processed module and skips the target module's own nodes */
+ if (node->module != collect_data->module) {
+ return LY_SUCCESS;
+ }
+
+ path = sid_node_path(node);
+ LY_CHECK_ERR_RET(!path, LOGMEM(collect_data->ctx), LY_EMEM);
+
+ rc = sid_item_add(collect_data, "data", path);
+ free(path);
+ return rc;
+}
+
+/**
+ * @brief Add assignment range to the sid-file data tree.
+ *
+ * @param[in] tree Sid-file root to add the range to.
+ * @param[in] entry_point First SID of the range.
+ * @param[in] size Number of SIDs in the range.
+ * @return LY_SUCCESS on success.
+ * @return LY_EMEM on memory allocation failure.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+sid_range_add(struct lyd_node *tree, uint64_t entry_point, uint64_t size)
+{
+ LY_ERR rc = LY_SUCCESS;
+ char size_str[21];
+ char *item_path = NULL;
+
+ /* the whole new range must fit inside the SID data type bound 2^63-1; */
+ LY_CHECK_ERR_GOTO(size - 1 > (((uint64_t)1 << 63) - 1) - entry_point,
+ (LOGERR(LYD_CTX(tree), LY_EINVAL,
+ "The assignment range [%" PRIu64 ", %" PRIu64 "] exceeds the SID data type bounds.",
+ entry_point, entry_point + size - 1), rc = LY_EINVAL), cleanup);
+
+ snprintf(size_str, sizeof size_str, "%" PRIu64, size);
+
+ LY_CHECK_ERR_GOTO(asprintf(&item_path, "assignment-range[entry-point='%" PRIu64 "']/size", entry_point) == -1,
+ rc = LY_EMEM, cleanup);
+ LY_CHECK_GOTO((rc = lyd_new_path(tree, NULL, item_path, size_str, 0, NULL)), cleanup);
+
+cleanup:
+ free(item_path);
+ return rc;
+}
+
+/**
+ * @brief Build the .sid file skeleton: root structure, module identity, status, description, dependency-revision list, and assignment-range list.
+ *
+ * @param[in] module Module used for module-name, module-revision, and dependency-revision entries.
+ * @param[in] ranges Array of assignment ranges.
+ * @param[in] range_count Number of elements in @p ranges.
+ * @param[in] version Value of the sid-file-version leaf, 0 to omit it
+ * @param[in] status Status of the SID file; for ::LYS_SID_FILE_PUBLISHED the "sid-file-status" leaf is
+ * omitted (its schema default is "published").
+ * @param[in] description Optional description string, NULL to auto-generate.
+ * @param[out] tree Generated /ietf-sid-file:sid-file node, NULL if creation failed.
+ * @return LY_SUCCESS on success.
+ * @return LY_EMEM on memory allocation failure.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+sid_build_skeleton(const struct lys_module *module, const struct sid_range *ranges, size_t range_count,
+ uint32_t version, LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **tree)
+{
+ LY_ERR rc = LY_SUCCESS;
+ const struct lysp_import *imports;
+ char ver_str[11];
+ char *item_path = NULL, *desc_buf = NULL, *time_str = NULL;
+ time_t now = time(NULL);
+ LY_ARRAY_COUNT_TYPE iter;
+
+ *tree = NULL;
+
+ LY_CHECK_GOTO((rc = lyd_new_path(NULL, module->ctx, "/ietf-sid-file:sid-file", NULL, 0, tree)), cleanup);
+
+ LY_CHECK_GOTO((rc = lyd_new_path(*tree, NULL, "module-name", module->name, 0, NULL)), cleanup);
+
+ if (module->revision) {
+ LY_CHECK_GOTO((rc = lyd_new_path(*tree, NULL, "module-revision", module->revision, 0, NULL)), cleanup);
+ }
+
+ if (version) {
+ snprintf(ver_str, sizeof ver_str, "%" PRIu32, version);
+ LY_CHECK_GOTO((rc = lyd_new_path(*tree, NULL, "sid-file-version", ver_str, 0, NULL)), cleanup);
+ }
+
+ if (status == LYS_SID_FILE_UNPUBLISHED) {
+ LY_CHECK_GOTO((rc = lyd_new_path(*tree, NULL, "sid-file-status", "unpublished", 0, NULL)), cleanup);
+ }
+
+ if (!description) {
+ /* auto-generate with libyang version and UTC timestamp */
+ LY_CHECK_GOTO((rc = ly_time_time2str(now, NULL, &time_str)), cleanup);
+ LY_CHECK_ERR_GOTO(asprintf(&desc_buf, "Generated by libyang %s, at %s", ly_version_so_str(), time_str) == -1,
+ rc = LY_EMEM, cleanup);
+ description = desc_buf;
+ }
+ LY_CHECK_GOTO((rc = lyd_new_path(*tree, NULL, "description", description, 0, NULL)), cleanup);
+ free(desc_buf);
+ desc_buf = NULL;
+
+ /* dependency-revision: the ietf-sid-file model requires the module revision here,
+ but the 'revision' statement is optional in YANG and some modules simply do
+ not have one, so it can happen that an import has no revision to record and the entry is skipped. */
+ imports = module->parsed->imports;
+ LY_ARRAY_FOR(imports, iter) {
+ if (imports[iter].module->revision) {
+ LY_CHECK_ERR_GOTO(asprintf(&item_path, "dependency-revision[module-name='%s']/module-revision",
+ imports[iter].name) == -1, rc = LY_EMEM, cleanup);
+ LY_CHECK_GOTO((rc = lyd_new_path(*tree, NULL, item_path, imports[iter].module->revision, 0, NULL)), cleanup);
+ free(item_path);
+ item_path = NULL;
+ }
+ }
+
+ /* One .sid file may legally declare several assignment ranges. */
+ for (size_t i = 0; i < range_count; i++) {
+ LY_CHECK_GOTO((rc = sid_range_add(*tree, ranges[i].entry_point, ranges[i].size)), cleanup);
+ }
+
+cleanup:
+ if (rc) {
+ lyd_free_all(*tree);
+ *tree = NULL;
+ }
+ free(item_path);
+ free(desc_buf);
+ free(time_str);
+ return rc;
+}
+
+/**
+ * @brief Collect all SID items of a module ("module", "identity", "feature", and "data" namespaces) and sort them.
+ *
+ * @param[in,out] callback_data Collection state: preallocated items array, capacity in max, ctx set for error logging.
+ * @param[in] module Compiled module to collect the items from.
+ * @return LY_SUCCESS on success, the sorted items and their count are in @p callback_data.
+ * @return LY_EINVAL if the capacity (the assignment range size) is too small for all collected items.
+ * @return LY_EMEM on memory allocation failure.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+sid_collect_items(struct sid_collect_data *callback_data, const struct lys_module *module)
+{
+ LY_ERR rc;
+ LY_ARRAY_COUNT_TYPE i;
+ uint32_t feature_idx = 0;
+ const struct lysp_feature *feature = NULL;
+ struct lysc_node **top = NULL;
+
+ /* module namespace: the module name itself (RFC 9595) */
+ LY_CHECK_RET((rc = sid_item_add(callback_data, "module", module->name)), rc);
+
+ /* module namespace: each submodule name (RFC 9595) */
+ LY_ARRAY_FOR(module->submodules, i) {
+ LY_CHECK_RET((rc = sid_item_add(callback_data, "module", module->submodules[i].name)), rc);
+ }
+
+ /* identity namespace: all identities defined in the module and its submodules. */
+ LY_ARRAY_FOR(module->identities, i) {
+ LY_CHECK_RET((rc = sid_item_add(callback_data, "identity", module->identities[i].name)), rc);
+ }
+
+ /* feature namespace: all features defined in the module and its submodules.*/
+ while ((feature = lysp_feature_next(feature, module->parsed, &feature_idx))) {
+ LY_CHECK_RET((rc = sid_item_add(callback_data, "feature", feature->name)), rc);
+ }
+
+ /* collect_data_cb attributes nodes to their defining module, so foreign
+ nodes are skipped whenever another module's tree is traversed below */
+ callback_data->module = module;
+
+ /* data namespace: walk the entire compiled schema tree depth-first.
+ lysc_module_dfs_full traverses all nodes including RPCs, actions,
+ notifications, input, output, choice and case nodes. sid_node_path() builds the
+ RFC 9595 schema-node-path identifiers (choice/case names omitted). */
+ LY_CHECK_RET((rc = lysc_module_dfs_full(module, collect_data_cb, callback_data)), rc);
+
+ /* data namespace: nodes that this module augments into other modules live in
+ the target modules' trees (RFC 9595 still assigns them to this module's .sid).
+ Traverse every context module that lists this module in its augmented_by and
+ collect the nodes defined here (collect_data_cb filters by defining module). */
+ {
+ const struct lys_module *aug_target;
+ uint32_t mod_idx = 0;
+
+ while ((aug_target = ly_ctx_get_module_iter(module->ctx, &mod_idx))) {
+ ly_bool augmented = 0;
+
+ if ((aug_target == module) || !aug_target->compiled) {
+ continue;
+ }
+ LY_ARRAY_FOR(aug_target->augmented_by, i) {
+ if (aug_target->augmented_by[i] == module) {
+ augmented = 1;
+ break;
+ }
+ }
+ if (augmented) {
+ LY_CHECK_RET((rc = lysc_module_dfs_full(aug_target, collect_data_cb, callback_data)), rc);
+ }
+ }
+ }
+
+ /* data namespace: also traverse the data trees of compiled top-level extension
+ instances that define their own data tree outside the standard module trees
+ (rc:yang-data, sx:structure); the top-level data node is obtained from the
+ generic compiled extension storage via lyplg_ext_get_storage_p(). */
+ LY_ARRAY_FOR(module->compiled->exts, i) {
+ lyplg_ext_get_storage_p(&module->compiled->exts[i], LY_STMT_DATA_NODE_MASK, (void ***)&top);
+
+ if (top) {
+ LY_CHECK_RET((rc = lysc_tree_dfs_full(*top, collect_data_cb, callback_data)), rc);
+ }
+ }
+
+ /* the range must cover all collected items; the excess is counted by sid_item_add */
+ LY_CHECK_RET(callback_data->count > callback_data->max, (LOGERR(module->ctx, LY_EINVAL, ".sid assignment range(s) size %" PRIu64 " is too small, %" PRIu64 " extra SID(s) are required.",
+ callback_data->max, callback_data->count - callback_data->max), LY_EINVAL));
+
+ qsort(callback_data->items, callback_data->count, sizeof(struct sid_item), compare_sid);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Free the collected items array including all owned identifiers.
+ *
+ * @param[in,out] callback_data Collection state; its items array is freed and set to NULL.
+ */
+static void
+sid_collect_data_free(struct sid_collect_data *callback_data)
+{
+ if (!callback_data || !callback_data->items) {
+ return;
+ }
+
+ /* The count may exceed the maximum capacity when the assignment range was too small. */
+ for (uint64_t i = 0; (i < callback_data->count) && (i < callback_data->max); i++) {
+ free(callback_data->items[i].ident);
+ }
+ free(callback_data->items);
+ callback_data->items = NULL;
+}
+
+/**
+ * @brief Emit an item entry into the sid-file data tree.
+ *
+ * @param[in] item Item to add to sid-file.
+ * @param[in, out] tree Sid-file root to add the item to.
+ * @return LY_SUCCESS on success.
+ * @return LY_EMEM on memory allocation failure.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+sid_emit_item(const struct sid_item *item, struct lyd_node *tree)
+{
+ LY_ERR rc = LY_SUCCESS;
+ char sid_str[21];
+ char *item_path = NULL;
+
+ snprintf(sid_str, sizeof sid_str, "%" PRIu64, item->sid);
+ LY_CHECK_ERR_GOTO(asprintf(&item_path, "item[namespace='%s'][identifier='%s']/sid", item->ns, item->ident) == -1,
+ rc = LY_EMEM, cleanup);
+ LY_CHECK_GOTO((rc = lyd_new_path(tree, NULL, item_path, sid_str, 0, NULL)), cleanup);
+ free(item_path);
+ item_path = NULL;
+
+ if (item->status) {
+ LY_CHECK_ERR_GOTO(asprintf(&item_path, "item[namespace='%s'][identifier='%s']/status", item->ns, item->ident) == -1,
+ rc = LY_EMEM, cleanup);
+ LY_CHECK_GOTO((rc = lyd_new_path(tree, NULL, item_path, item->status, 0, NULL)), cleanup);
+ free(item_path);
+ item_path = NULL;
+ }
+
+cleanup:
+ free(item_path);
+ return rc;
+}
+
+LY_ERR
+sid_file_gen(const struct lys_module *module, uint64_t entry_point, uint64_t size,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct lyd_node *tree = NULL;
+ struct sid_item *items = NULL;
+ struct sid_collect_data cb_data = {0};
+ struct sid_range range = {entry_point, size};
+ uint64_t sid;
+
+ /* --- Phase 1: build the sid-file skeleton --- */
+ LY_CHECK_GOTO((rc = sid_build_skeleton(module, &range, 1, 0, status, description, &tree)), cleanup);
+
+ /* --- Phase 2: collect items from the compiled schema and sort --- */
+ items = calloc(size, sizeof *items);
+ LY_CHECK_ERR_GOTO(!items, rc = LY_EMEM, cleanup);
+
+ cb_data.items = items;
+ cb_data.max = size;
+ cb_data.ctx = module->ctx;
+
+ LY_CHECK_GOTO((rc = sid_collect_items(&cb_data, module)), cleanup);
+
+ /* --- Phase 3: assign SIDs and build the item list --- */
+
+ /* assign sequential SIDs in sorted order */
+ sid = entry_point;
+ for (uint64_t i = 0; i < cb_data.count; i++) {
+ items[i].sid = sid++;
+ items[i].status = (status == LYS_SID_FILE_UNPUBLISHED) ? (char *)"unstable" : NULL;
+
+ LY_CHECK_GOTO((rc = sid_emit_item(&items[i], tree)), cleanup);
+ }
+
+ *sid_file = tree;
+ tree = NULL;
+
+cleanup:
+ lyd_free_all(tree);
+ sid_collect_data_free(&cb_data);
+ return rc;
+}
+
+/**
+ * @brief One item extracted from a previous .sid file.
+ *
+ * All strings inside @p item are OWNED by this array entry (strdup'd during
+ * extraction) and freed per entry by ::sid_old_items_free.
+ */
+struct sid_old_item {
+ struct sid_item item; /**< Namespace/identifier/SID/status from the previous file. */
+ ly_bool matched; /**< true once a current schema item claims this entry during merge.
+ * An obsolete item matched back into the schema keeps its SID and
+ * is revived: its status is cleared to stable (NULL) at merge time. */
+};
+
+/**
+ * @brief Comparator for qsort that sorts previous items the same way as ::compare_sid
+ *
+ * Sort order alphabetical:
+ * 1. Namespace descending.
+ * 2. Identifier ascending.
+ *
+ * @param[in] a First item (struct sid_old_item *).
+ * @param[in] b Second item (struct sid_old_item *).
+ * @return <0 if @p a comes before @p b, 0 if equal, >0 if @p a comes after @p b.
+ */
+static int
+compare_old(const void *a, const void *b)
+{
+ const struct sid_old_item *item_a = a, *item_b = b;
+
+ return compare_sid(&item_a->item, &item_b->item);
+}
+
+/**
+ * @brief Look up an item by (namespace, identifier) in the sorted array of
+ * previous items.
+ *
+ * The array must be sorted with ::compare_old and must not contain duplicate
+ * (namespace, identifier) keys - when the previous file has duplicates, the
+ * first occurrence is kept during extraction and the rest is dropped.
+ *
+ * @param[in] olds Sorted array of previous items.
+ * @param[in] count Number of elements in @p olds.
+ * @param[in] ns Namespace of the item.
+ * @param[in] ident Identifier of the item.
+ * @return Pointer to the matching item.
+ * @return NULL if not present.
+ */
+static struct sid_old_item *
+sid_old_find(const struct sid_old_item *olds, uint64_t count, const char *ns, const char *ident)
+{
+ uint64_t lo = 0, hi = count, mid;
+ int cmp;
+
+ while (lo < hi) {
+ mid = lo + (hi - lo) / 2;
+ if (olds[mid].item.ns[0] == ns[0]) {
+ cmp = strcmp(ident, olds[mid].item.ident);
+ } else {
+ cmp = olds[mid].item.ns[0] - ns[0];
+ }
+ if (!cmp) {
+ return (struct sid_old_item *)&olds[mid];
+ } else if (cmp < 0) {
+ hi = mid;
+ } else {
+ lo = mid + 1;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief Free an array of previous items including all owned strings.
+ *
+ * @param[in,out] olds Array to free, set to NULL afterwards.
+ * @param[in] count Number of elements in @p olds.
+ */
+static void
+sid_old_items_free(struct sid_old_item **olds, uint64_t count)
+{
+ if (*olds) {
+ for (uint64_t i = 0; i < count; i++) {
+ free((*olds)[i].item.ns);
+ free((*olds)[i].item.ident);
+ free((*olds)[i].item.status);
+ }
+ free(*olds);
+ *olds = NULL;
+ }
+}
+
+/**
+ * @brief Get the canonical string value of a direct leaf child of a data node.
+ *
+ * @param[in] node Parent data node (sid-file root or a list instance).
+ * @param[in] name Schema name of the leaf child.
+ * @return Canonical value (borrowed, do not free).
+ * @return NULL if the leaf is missing.
+ */
+static const char *
+sid_child_value(const struct lyd_node *node, const char *name)
+{
+ const struct lyd_node *child;
+
+ LY_LIST_FOR(lyd_child(node), child) {
+ if (!strcmp(child->schema->name, name)) {
+ return lyd_get_value(child);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief Find a specific child terminal node (leaf or leaf-list) by schema name.
+ *
+ * @param[in] node Parent data node whose children will be searched.
+ * @param[in] name Schema identifier (name) of the target child node to match.
+ *
+ * @return Pointer to the matched terminal node (`struct lyd_node_term *`).
+ * @return NULL if no matching child is found.
+ */
+static struct lyd_node_term *
+sid_child_term(const struct lyd_node *node, const char *name)
+{
+ const struct lyd_node *child;
+
+ LY_LIST_FOR(lyd_child(node), child) {
+ if (!strcmp(child->schema->name, name)) {
+ return (struct lyd_node_term *)child;
+ }
+ }
+ return NULL;
+}
+
+LY_ERR
+sid_range_append(struct lyd_node *tree, uint64_t entry_point, uint64_t size)
+{
+ LY_ERR rc = LY_SUCCESS;
+ const struct lyd_node *child = NULL;
+ uint64_t ep = 0, sz = 0;
+ struct lyd_node_term *term = NULL;
+
+ LY_CHECK_ERR_GOTO(!tree->schema || strcmp(tree->schema->name, "sid-file"),
+ (LOGERR(LYD_CTX(tree), LY_EINVAL,
+ "Invalid previous .sid file data tree (expected the \"sid-file\" top node)."),
+ rc = LY_EINVAL), cleanup);
+
+ /* the new range must not overlap any already declared assignment-range */
+ for (child = lyd_child(tree); child; child = child->next) {
+ if (strcmp(child->schema->name, "assignment-range")) {
+ continue;
+ }
+ term = sid_child_term(child, "entry-point");
+ LY_CHECK_ERR_GOTO(!term,
+ (LOGERR(LYD_CTX(tree), LY_EINVAL, "Missing required data in the previous .sid file."), rc = LY_EINVAL), cleanup);
+ ep = term->value.uint64;
+ term = sid_child_term(child, "size");
+ LY_CHECK_ERR_GOTO(!term,
+ (LOGERR(LYD_CTX(tree), LY_EINVAL, "Missing required data in the previous .sid file."), rc = LY_EINVAL), cleanup);
+ sz = term->value.uint64;
+
+ /* unsigned wrap-around makes a single subtraction sufficient per direction */
+ LY_CHECK_ERR_GOTO((ep - entry_point < size) || (entry_point - ep < sz),
+ (LOGERR(LYD_CTX(tree), LY_EINVAL,
+ "The assignment range [%" PRIu64 ", %" PRIu64 "] overlaps the existing assignment range [%" PRIu64 ", %" PRIu64 "].",
+ entry_point, entry_point + size - 1, ep, ep + sz - 1), rc = LY_EINVAL), cleanup);
+ }
+
+ rc = sid_range_add(tree, entry_point, size);
+
+cleanup:
+ return rc;
+}
+
+/**
+ * @brief Extract the data needed to update an existing .sid file.
+ *
+ * @param[in] module Module the file belongs to; its name must match the file.
+ * @param[in] prev Root node of the previous .sid data tree.
+ * @param[out] ranges Newly allocated assignment ranges from the file.
+ * @param[out] ranges_count Number of elements in @p ranges.
+ * @param[out] version sid-file-version from the file, 0 if the leaf is absent.
+ * @param[out] items Newly allocated items with dense entries (duplicate keys excluded), in file order; free with ::sid_old_items_free.
+ * @param[out] items_count Number of used entries in @p items.
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL on invalid file content (name mismatch, missing data, no ranges).
+ * @return LY_EMEM on memory allocation failure.
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+sid_extract_file(const struct lys_module *module, const struct lyd_node *prev, struct sid_range **ranges,
+ size_t *ranges_count, uint32_t *version, struct sid_old_item **items, uint64_t *items_count)
+{
+ LY_ERR rc = LY_SUCCESS;
+ const struct lyd_node *child = NULL;
+ struct sid_range *extracted_ranges = NULL;
+ struct sid_old_item *extracted_items = NULL;
+ size_t range_idx = 0, total_ranges = 0;
+ uint64_t item_idx = 0, total_items = 0, sid_value;
+ const char *name = NULL, *ns = NULL, *ident = NULL, *status = NULL;
+ char *ns_copy = NULL, *ident_copy = NULL, *status_copy = NULL;
+ struct lyd_node_term *term = NULL;
+ ly_bool duplicate = 0;
+
+ /* the leaf is optional with default 0 in the schema */
+ *version = 0;
+
+ /* module identity, version, counts of both lists */
+ LY_LIST_FOR(lyd_child(prev), child) {
+ if (!child->schema) {
+ continue;
+ }
+ if (!strcmp(child->schema->name, "module-name")) {
+ name = lyd_get_value(child);
+ LY_CHECK_ERR_GOTO(strcmp(name, module->name),
+ (LOGERR(module->ctx, LY_EINVAL, "The .sid file module name \"%s\" does not match the "
+ "module \"%s\".", name, module->name), rc = LY_EINVAL), cleanup);
+ } else if (!strcmp(child->schema->name, "sid-file-version")) {
+ *version = ((const struct lyd_node_term *)child)->value.uint32;
+ } else if (!strcmp(child->schema->name, "assignment-range")) {
+ total_ranges++;
+ } else if (!strcmp(child->schema->name, "item")) {
+ total_items++;
+ }
+ }
+
+ LY_CHECK_ERR_GOTO(!total_ranges,
+ (LOGERR(module->ctx, LY_EINVAL, "The .sid file \"%s\" has no assignment-range.",
+ module->name), rc = LY_EINVAL), cleanup);
+
+ extracted_ranges = calloc(total_ranges, sizeof *extracted_ranges);
+ LY_CHECK_ERR_GOTO(!extracted_ranges, (LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+ if (total_items) {
+ extracted_items = calloc(total_items, sizeof *extracted_items);
+ LY_CHECK_ERR_GOTO(!extracted_items, (LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+ }
+
+ /* fill ranges and items */
+ LY_LIST_FOR(lyd_child(prev), child) {
+ if (!child->schema) {
+ continue;
+ }
+
+ if (!strcmp(child->schema->name, "assignment-range")) {
+ term = sid_child_term(child, "entry-point");
+ LY_CHECK_ERR_GOTO(!term,
+ (LOGERR(module->ctx, LY_EINVAL, "Missing required data in the previous .sid file."),
+ rc = LY_EINVAL), cleanup);
+ extracted_ranges[range_idx].entry_point = term->value.uint64;
+
+ term = sid_child_term(child, "size");
+ LY_CHECK_ERR_GOTO(!term,
+ (LOGERR(module->ctx, LY_EINVAL, "Missing required data in the previous .sid file."),
+ rc = LY_EINVAL), cleanup);
+ extracted_ranges[range_idx].size = term->value.uint64;
+ range_idx++;
+
+ } else if (!strcmp(child->schema->name, "item")) {
+ ns = sid_child_value(child, "namespace");
+ ident = sid_child_value(child, "identifier");
+ term = sid_child_term(child, "sid");
+ LY_CHECK_ERR_GOTO(!ns || !ident || !term,
+ (LOGERR(module->ctx, LY_EINVAL, "Missing required data in the previous .sid file."),
+ rc = LY_EINVAL), cleanup);
+ sid_value = term->value.uint64;
+
+ /* duplicate keys: the first occurrence wins */
+ duplicate = 0;
+ for (uint64_t i = 0; i < item_idx; i++) {
+ if (!strcmp(extracted_items[i].item.ns, ns) && !strcmp(extracted_items[i].item.ident, ident)) {
+ duplicate = 1;
+ break;
+ }
+ }
+ if (duplicate) {
+ continue;
+ }
+
+ status = sid_child_value(child, "status");
+
+ ns_copy = strdup(ns);
+ LY_CHECK_ERR_GOTO(!ns_copy, (LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+ ident_copy = strdup(ident);
+ LY_CHECK_ERR_GOTO(!ident_copy, (free(ns_copy), LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+ /* "stable" is the schema default and is stored as NULL */
+ status_copy = (status && strcmp(status, "stable")) ? strdup(status) : NULL;
+ LY_CHECK_ERR_GOTO(status && strcmp(status, "stable") && !status_copy,
+ (free(ns_copy), free(ident_copy), LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+
+ extracted_items[item_idx].item.ns = ns_copy;
+ extracted_items[item_idx].item.ident = ident_copy;
+ extracted_items[item_idx].item.sid = sid_value;
+ extracted_items[item_idx].item.status = status_copy;
+ extracted_items[item_idx].matched = 0;
+ item_idx++;
+ }
+ }
+
+ *ranges = extracted_ranges;
+ *ranges_count = total_ranges;
+ *items = extracted_items;
+ *items_count = item_idx;
+ return LY_SUCCESS;
+
+cleanup:
+ free(extracted_ranges);
+ sid_old_items_free(&extracted_items, item_idx);
+ return rc;
+}
+
+/**
+ * @brief Comparator for qsort that sorts assignment ranges by entry-point ascending.
+ *
+ * @param[in] a First range (struct sid_range *).
+ * @param[in] b Second range (struct sid_range *).
+ * @return <0 if @p a comes before @p b, 0 if equal, >0 if @p a comes after @p b.
+ */
+static int
+compare_range(const void *a, const void *b)
+{
+ const struct sid_range *ra = a, *rb = b;
+
+ if (ra->entry_point == rb->entry_point) {
+ return 0;
+ }
+ return (ra->entry_point > rb->entry_point) ? 1 : -1;
+}
+
+LY_ERR
+sid_file_update(const struct lys_module *module, const struct lyd_node *prev_sid_file,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct sid_range *ranges = NULL;
+ struct sid_old_item *olds = NULL, *match = NULL;
+ struct sid_item *items = NULL, *merged = NULL;
+ struct sid_collect_data cb_data = {0};
+ uint64_t *next_free = NULL;
+ size_t ranges_count = 0, alloc_range_idx = 0;
+ uint64_t old_count = 0, capacity = 0, merged_count = 0, extra = 0;
+ uint32_t version = 0;
+ ly_bool in_range = 0;
+ struct lyd_node *tree = NULL;
+
+ /* --- step 1: validation and extraction from the previous file --- */
+ LY_CHECK_ERR_GOTO(!prev_sid_file->schema || strcmp(prev_sid_file->schema->name, "sid-file"),
+ (LOGERR(module->ctx, LY_EINVAL,
+ "Invalid previous .sid file data tree (expected the \"sid-file\" top node)."),
+ rc = LY_EINVAL), cleanup);
+
+ LY_CHECK_GOTO((rc = sid_extract_file(module, prev_sid_file,
+ &ranges, &ranges_count, &version, &olds, &old_count)), cleanup);
+
+ /* assignment order: ranges ascending by entry-point */
+ qsort(ranges, ranges_count, sizeof *ranges, compare_range);
+
+ /* every old SID must lie inside some declared range; track the highest used SID per range so new items start right after it */
+ next_free = calloc(ranges_count, sizeof *next_free);
+ LY_CHECK_ERR_GOTO(!next_free, (LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+ for (size_t j = 0; j < ranges_count; j++) {
+ next_free[j] = ranges[j].entry_point;
+ }
+ for (uint64_t i = 0; i < old_count; i++) {
+ in_range = 0;
+ for (size_t j = 0; j < ranges_count; j++) {
+ if ((olds[i].item.sid >= ranges[j].entry_point) && (olds[i].item.sid - ranges[j].entry_point < ranges[j].size)) {
+ in_range = 1;
+ if (olds[i].item.sid >= next_free[j]) {
+ next_free[j] = olds[i].item.sid + 1;
+ }
+ break;
+ }
+ }
+ LY_CHECK_ERR_GOTO(!in_range,
+ (LOGERR(module->ctx, LY_EINVAL,
+ "The previous .sid file assigns SID %" PRIu64 " (\"%s\"), which is "
+ "outside of any assignment range.", olds[i].item.sid, olds[i].item.ident),
+ rc = LY_EINVAL), cleanup);
+ }
+
+ /* --- step 2: collect current schema items --- */
+ for (size_t i = 0; i < ranges_count; i++) {
+ capacity += ranges[i].size;
+ }
+ items = calloc(capacity, sizeof *items);
+ LY_CHECK_ERR_GOTO(!items, (LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+
+ cb_data.items = items;
+ cb_data.max = capacity;
+ cb_data.ctx = module->ctx;
+
+ LY_CHECK_GOTO((rc = sid_collect_items(&cb_data, module)), cleanup);
+
+ /* --- step 3: merge collected items with previous items --- */
+
+ /* sort olds by (namespace, identifier) for binary lookup */
+ qsort(olds, old_count, sizeof *olds, compare_old);
+
+ /* merged array holds: matched items (old SID), new items (free SID), and obsolete items */
+ merged = calloc(cb_data.count + old_count, sizeof *merged);
+ LY_CHECK_ERR_GOTO(!merged, (LOGMEM(module->ctx), rc = LY_EMEM), cleanup);
+
+ for (uint64_t i = 0; i < cb_data.count; i++) {
+ match = sid_old_find(olds, old_count, cb_data.items[i].ns, cb_data.items[i].ident);
+ if (match) {
+ match->matched = 1;
+ merged[merged_count].ns = cb_data.items[i].ns;
+ merged[merged_count].ident = cb_data.items[i].ident;
+ merged[merged_count].sid = match->item.sid;
+ /* preserve old status; obsolete-matched is revived to stable (NULL) */
+ merged[merged_count].status = (match->item.status && strcmp(match->item.status, "obsolete")) ?
+ match->item.status : NULL;
+ } else {
+ /* new item: first SID after the highest used one, walking ranges forward */
+ for ( ;; ) {
+ if (alloc_range_idx >= ranges_count) {
+ /* count the remaining items (this one included) that still need a new SID */
+ for (uint64_t j = i; j < cb_data.count; j++) {
+ if (!sid_old_find(olds, old_count, cb_data.items[j].ns, cb_data.items[j].ident)) {
+ extra++;
+ }
+ }
+ LOGERR(module->ctx, LY_EINVAL,
+ ".sid assignment range(s) size %" PRIu64 " is too small, %" PRIu64 " extra SID(s) are required.",
+ capacity, extra);
+ rc = LY_EINVAL;
+ goto cleanup;
+ }
+ if (next_free[alloc_range_idx] - ranges[alloc_range_idx].entry_point <
+ ranges[alloc_range_idx].size) {
+ break;
+ }
+ alloc_range_idx++;
+ }
+ merged[merged_count].ns = cb_data.items[i].ns;
+ merged[merged_count].ident = cb_data.items[i].ident;
+ merged[merged_count].sid = next_free[alloc_range_idx]++;
+ merged[merged_count].status = (status == LYS_SID_FILE_UNPUBLISHED) ? "unstable" : NULL;
+ }
+ merged_count++;
+ }
+
+ /* unmatched old items are kept as obsolete (RFC 9595: MUST NOT be removed) */
+ for (uint64_t i = 0; i < old_count; i++) {
+ if (!olds[i].matched) {
+ merged[merged_count] = olds[i].item;
+ merged[merged_count].status = (char *)"obsolete";
+ merged_count++;
+ }
+ }
+
+ /* --- step 4: build the updated .sid file data tree --- */
+
+ LY_CHECK_GOTO((rc = sid_build_skeleton(module, ranges, ranges_count, version + 1,
+ status, description, &tree)), cleanup);
+
+ /* published files do not contain unstable items (finalize) */
+ for (uint64_t i = 0; i < merged_count; i++) {
+ if (status == LYS_SID_FILE_PUBLISHED) {
+ if (merged[i].status && !strcmp(merged[i].status, "unstable")) {
+ merged[i].status = NULL;
+ }
+ }
+
+ LY_CHECK_GOTO((rc = sid_emit_item(&merged[i], tree)), cleanup);
+ }
+
+ *sid_file = tree;
+ tree = NULL;
+
+cleanup:
+ lyd_free_all(tree);
+ free(merged);
+ free(next_free);
+ free(ranges);
+ sid_old_items_free(&olds, old_count);
+ sid_collect_data_free(&cb_data);
+ return rc;
+}
diff --git a/src/printer_tree.c b/src/printer_tree.c
index ba01aff687..e69ee3b919 100644
--- a/src/printer_tree.c
+++ b/src/printer_tree.c
@@ -3111,7 +3111,7 @@ pt_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i)
if (lysc_tree) {
ce = exts;
while (*i < LY_ARRAY_COUNT(ce)) {
- if (ce->def->plugin_ref && pt_ext_parent_is_valid(1, &ce[*i])) {
+ if (ce[*i].def->plugin_ref && pt_ext_parent_is_valid(1, &ce[*i])) {
ext = &ce[*i];
break;
}
@@ -3137,19 +3137,27 @@ pt_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i)
* @param[in] tc Contains current node.
* @param[in] ext_name Extension name to find.
* @param[in] from_module Set to 1 if extensions in the module
- * sould be searched otherwise it will search in the node.
+ * should be searched otherwise it will search in the node.
+ * @param[in] origin_lysc_tree Optional parameter, if set then
+ * reset @p tc to the original lysc tree before iteration over
+ * next extension. If NULL then reset is not applied.
* @param[in,out] i State of iterator.
* @return First/next extension or NULL.
*/
static void *
-pt_ext_iter(const struct pt_tree_ctx *tc, const char *ext_name,
- ly_bool from_module, LY_ARRAY_COUNT_TYPE *i)
+pt_ext_iter(struct pt_tree_ctx *tc, const char *ext_name,
+ ly_bool from_module, const ly_bool *origin_lysc_tree,
+ LY_ARRAY_COUNT_TYPE *i)
{
struct lysp_ext_instance *ext_pars;
struct lysc_ext_instance *ext_comp;
void *ext = NULL;
const char *name = "";
+ if (origin_lysc_tree) {
+ tc->lysc_tree = *origin_lysc_tree;
+ }
+
do {
if (tc->lysc_tree) {
ext_comp = from_module ? tc->cmod->exts : tc->cn->exts;
@@ -3182,7 +3190,7 @@ pt_ext_is_present(struct pt_tree_ctx *tc, const char *ext_name)
{
uint64_t i = 0;
- if (pt_ext_iter(tc, ext_name, 0, &i)) {
+ if (pt_ext_iter(tc, ext_name, 0, NULL, &i)) {
return 1;
} else {
return 0;
@@ -3418,7 +3426,7 @@ pt_print_schema_mount(struct pt_wrapper wr, struct pt_parent_cache ca,
/* load children of mount-point */
i = 0;
- while ((ext = pt_ext_iter(&tc, "mount-point", 0, &i))) {
+ while ((ext = pt_ext_iter(&tc, "mount-point", 0, NULL, &i))) {
rc = pt_create_mount_point(tc.lysc_tree, ext, &schema_mount);
LY_CHECK_ERR_GOTO(rc, tc.last_error = rc, end);
@@ -3881,6 +3889,7 @@ pt_ext_read(void *ext, ly_bool *compiled, struct pt_keyword_stmt *ks)
void *schema;
if (!*compiled) {
+ /* lysp tree */
ext_pars = ext;
ks->argument = ext_pars->argument;
name = strchr(ext_pars->name, ':') + 1;
@@ -3891,9 +3900,9 @@ pt_ext_read(void *ext, ly_bool *compiled, struct pt_keyword_stmt *ks)
} else {
schema = pt_ext_parsed_read_storage(ext_pars, LY_STMT_DATA_NODE_MASK);
}
- *compiled = 0;
return schema;
}
+ /* else lysc tree */
/* for compiled extension instance */
ext_comp = ext;
@@ -3902,19 +3911,19 @@ pt_ext_read(void *ext, ly_bool *compiled, struct pt_keyword_stmt *ks)
/* search in lysc_ext_instance */
lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, sizeof schema, (const void **)&schema);
- *compiled = 1;
if (schema) {
return schema;
}
/* no data nodes lysc_ext_instance, so search in lysp_ext_instance */
- *compiled = 0;
if (!strcmp(ks->section_name, "augment-structure")) {
lyplg_ext_parsed_get_storage(ext_comp, LY_STMT_AUGMENT, sizeof schema, (const void **)&schema);
schema = ((struct lysp_node_augment *)schema)->child;
} else {
lyplg_ext_parsed_get_storage(ext_comp, LY_STMT_DATA_NODE_MASK, sizeof schema, (const void **)&schema);
}
+ /* switching from lysc tree to lysp tree */
+ *compiled = 0;
return schema;
}
@@ -3939,9 +3948,7 @@ pt_print_extensions(struct pt_tree_ctx tc)
tc.plugin_ctx.schema = &ext_schema;
tc.plugin_ctx.schema->ext = PT_EXT_GENERIC;
- while ((ext = pt_ext_iter(&tc, NULL, 1, &i))) {
- tc.lysc_tree = origin_lysc_tree;
-
+ while ((ext = pt_ext_iter(&tc, NULL, 1, &origin_lysc_tree, &i))) {
schema = pt_ext_read(ext, &tc.lysc_tree, &ks);
if (!strcmp(ks.section_name, "mount-point") ||
!strcmp(ks.section_name, "annotation")) {
@@ -3967,8 +3974,6 @@ pt_print_extensions(struct pt_tree_ctx tc)
/* print subtree */
node = pt_modi_first_sibling(PT_EMPTY_PARENT_CACHE, &tc);
pt_print_siblings(&node, PT_INIT_WRAPPER_BODY, PT_EMPTY_PARENT_CACHE, &tc);
-
- tc.lysc_tree = origin_lysc_tree;
}
}
diff --git a/src/printer_xml.c b/src/printer_xml.c
index e04a2aaacd..07d7dde78d 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -129,6 +129,7 @@ xml_print_ns_opaq(struct xmlpr_ctx *pctx, LY_VALUE_FORMAT format, const struct l
return xml_print_ns(pctx, name->module_ns, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : name->prefix, prefix_opts);
}
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
if (name->module_name) {
mod = ly_ctx_get_module_latest(pctx->ctx, name->module_name);
diff --git a/src/schema_compile.c b/src/schema_compile.c
index cc130cbfdc..828dd6a318 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -51,58 +51,52 @@
void
lysc_update_path(struct lysc_ctx *ctx, const struct lys_module *parent_module, const char *name)
{
- int len;
- uint8_t nextlevel = 0; /* 0 - no starttag, 1 - '/' starttag, 2 - '=' starttag + '}' endtag */
+ ly_bool spec = 0;
if (!name) {
+ assert(ctx->path_used);
+
/* removing last path segment */
- if (ctx->path[ctx->path_len - 1] == '}') {
- for ( ; ctx->path[ctx->path_len] != '=' && ctx->path[ctx->path_len] != '{'; --ctx->path_len) {}
- if (ctx->path[ctx->path_len] == '=') {
- ctx->path[ctx->path_len++] = '}';
+ if (ctx->path[ctx->path_used - 1] == '}') {
+ for ( ; ctx->path[ctx->path_used] != '=' && ctx->path[ctx->path_used] != '{'; --ctx->path_used) {}
+ if (ctx->path[ctx->path_used] == '=') {
+ ctx->path[ctx->path_used++] = '}';
} else {
/* not a top-level special tag, remove also preceiding '/' */
goto remove_nodelevel;
}
} else {
remove_nodelevel:
- for ( ; ctx->path[ctx->path_len] != '/'; --ctx->path_len) {}
- if (ctx->path_len == 0) {
- /* top-level (last segment) */
- ctx->path_len = 1;
+ for ( ; ctx->path[ctx->path_used] != '/'; --ctx->path_used) {}
+ if (!ctx->path_used) {
+ free(ctx->path);
+ ctx->path = NULL;
+ ctx->path_size = 0;
}
}
- /* set new terminating NULL-byte */
- ctx->path[ctx->path_len] = '\0';
+
+ if (ctx->path_used) {
+ /* set new terminating NULL-byte */
+ ctx->path[ctx->path_used] = '\0';
+ }
} else {
- if (ctx->path_len > 1) {
- if (!parent_module && (ctx->path[ctx->path_len - 1] == '}') && (ctx->path[ctx->path_len - 2] != '\'')) {
- /* extension of the special tag */
- nextlevel = 2;
- --ctx->path_len;
- } else {
- /* there is already some path, so add next level */
- nextlevel = 1;
- }
- } /* else the path is just initiated with '/', so do not add additional slash in case of top-level nodes */
+ if (!parent_module && ctx->path_used && (ctx->path[ctx->path_used - 1] == '}') &&
+ (ctx->path[ctx->path_used - 2] != '\'')) {
+ /* extension of the special tag */
+ spec = 1;
+ --ctx->path_used;
+ }
- if (nextlevel != 2) {
- if ((parent_module && (parent_module == ctx->cur_mod)) || (!parent_module && (ctx->path_len > 1) && (name[0] == '{'))) {
+ if (!spec) {
+ if ((parent_module && (parent_module == ctx->cur_mod)) || (!parent_module && (ctx->path_used > 1) &&
+ (name[0] == '{'))) {
/* module not changed, print the name unprefixed */
- len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s",
- nextlevel ? "/" : "", name);
+ ly_append_str(&ctx->path, &ctx->path_size, &ctx->path_used, "/%s", name);
} else {
- len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s:%s",
- nextlevel ? "/" : "", ctx->cur_mod->name, name);
+ ly_append_str(&ctx->path, &ctx->path_size, &ctx->path_used, "/%s:%s", ctx->cur_mod->name, name);
}
} else {
- len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "='%s'}", name);
- }
- if (len >= LYSC_CTX_BUFSIZE - (int)ctx->path_len) {
- /* output truncated */
- ctx->path_len = LYSC_CTX_BUFSIZE - 1;
- } else {
- ctx->path_len += len;
+ ly_append_str(&ctx->path, &ctx->path_size, &ctx->path_used, "='%s'}", name);
}
}
@@ -368,11 +362,12 @@ lys_compile_identity_bases(struct lysc_ctx *ctx, const struct lysp_module *base_
static LY_ERR
lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident **idents)
{
+ LY_ERR rc = LY_SUCCESS;
LY_ARRAY_COUNT_TYPE u, v;
lysc_update_path(ctx, NULL, "{identity}");
- for (u = 0; u < LY_ARRAY_COUNT(*idents); ++u) {
+ for (u = 0; !rc && (u < LY_ARRAY_COUNT(*idents)); ++u) {
/* find matching parsed identity */
for (v = 0; v < LY_ARRAY_COUNT(idents_p); ++v) {
if (idents_p[v].name == (*idents)[u].name) {
@@ -386,12 +381,12 @@ lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p
}
lysc_update_path(ctx, NULL, (*idents)[u].name);
- LY_CHECK_RET(lys_compile_identity_bases(ctx, ctx->pmod, idents_p[v].bases, &(*idents)[u], NULL));
+ rc = lys_compile_identity_bases(ctx, ctx->pmod, idents_p[v].bases, &(*idents)[u], NULL);
lysc_update_path(ctx, NULL, NULL);
}
lysc_update_path(ctx, NULL, NULL);
- return LY_SUCCESS;
+ return rc;
}
LY_ERR
@@ -597,6 +592,7 @@ lys_compile_unres_when(struct lysc_ctx *ctx, const struct lysc_when *when, const
uint32_t i, opts;
struct lysc_node *schema;
LY_ERR ret = LY_SUCCESS;
+ char *path;
opts = LYXP_SCNODE_SCHEMA | ((node->flags & LYS_IS_OUTPUT) ? LYXP_SCNODE_OUTPUT : 0);
@@ -610,8 +606,13 @@ lys_compile_unres_when(struct lysc_ctx *ctx, const struct lysc_when *when, const
goto cleanup;
}
- ctx->path[0] = '\0';
- lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+ path = lysc_path(node, LYSC_PATH_LOG, NULL, 0);
+ LY_CHECK_ERR_GOTO(!path, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ free(ctx->path);
+ ctx->path = path;
+ ctx->path_used = strlen(ctx->path);
+ ctx->path_size = ctx->path_used + 1;
+
for (i = 0; i < tmp_set.used; ++i) {
if (tmp_set.val.scnodes[i].type != LYXP_NODE_ELEM) {
/* skip roots'n'stuff */
@@ -684,6 +685,7 @@ lys_compile_unres_must(struct lysc_ctx *ctx, const struct lysc_node *node, const
LY_ARRAY_COUNT_TYPE u;
struct lysc_must *musts;
LY_ERR ret = LY_SUCCESS;
+ char *path;
uint16_t flg;
memset(&tmp_set, 0, sizeof tmp_set);
@@ -701,8 +703,13 @@ lys_compile_unres_must(struct lysc_ctx *ctx, const struct lysc_node *node, const
goto cleanup;
}
- ctx->path[0] = '\0';
- lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+ path = lysc_path(node, LYSC_PATH_LOG, NULL, 0);
+ LY_CHECK_ERR_GOTO(!path, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+ free(ctx->path);
+ ctx->path = path;
+ ctx->path_used = strlen(ctx->path);
+ ctx->path_size = ctx->path_used + 1;
+
for (i = 0; i < tmp_set.used; ++i) {
/* skip roots'n'stuff */
if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
@@ -868,6 +875,7 @@ lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, st
{
const struct lysc_node *target = NULL;
struct ly_path *p;
+ char *path;
uint16_t flg;
assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
@@ -894,10 +902,14 @@ lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, st
return LY_EVALID;
}
+ path = lysc_path(node, LYSC_PATH_LOG, NULL, 0);
+ LY_CHECK_ERR_RET(!path, LOGMEM(ctx->ctx), LY_EMEM);
+ free(ctx->path);
+ ctx->path = path;
+ ctx->path_used = strlen(ctx->path);
+ ctx->path_size = ctx->path_used + 1;
+
/* check status */
- ctx->path[0] = '\0';
- lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
- ctx->path_len = strlen(ctx->path);
if (node->module == local_mod->mod) {
/* use flags of the context node since the definition is local */
flg = node->flags;
@@ -908,8 +920,6 @@ lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, st
if (lysc_check_status(ctx, node, flg, local_mod->mod, node->name, target->flags, target->module, target->name)) {
return LY_EVALID;
}
- ctx->path_len = 1;
- ctx->path[1] = '\0';
/* check config */
if (lref->require_instance) {
@@ -1483,6 +1493,7 @@ lys_compile_unres_depset(struct ly_ctx *ctx, struct lys_glob_unres *unres)
}
cleanup:
+ free(cctx.path);
return ret;
}
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 68669e3db4..d6f3b04506 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -52,11 +52,11 @@ struct lysc_ctx {
struct ly_set uses_augs; /**< set of compiled non-applied uses augments (stored ::lysc_augment *) */
struct ly_set uses_rfns; /**< set of compiled non-applied uses refines (stored ::lysc_refine *) */
struct lys_depset_unres *unres; /**< dependency set unres sets */
- uint32_t path_len; /**< number of path bytes used */
uint32_t compile_opts; /**< various @ref scflags. */
-#define LYSC_CTX_BUFSIZE 4078
- char path[LYSC_CTX_BUFSIZE];/**< Path identifying the schema node currently being processed */
+ char *path; /**< Path identifying the schema node currently being processed */
+ uint32_t path_used; /**< number of path bytes used (without terminating 0) */
+ uint32_t path_size; /**< allocated size of path */
};
/**
@@ -66,9 +66,7 @@ struct lysc_ctx {
* @param[in] CTX libyang context.
*/
#define LYSC_CTX_INIT_CTX(CCTX, CTX) \
- (CCTX).ctx = (CTX); \
- (CCTX).path_len = 1; \
- (CCTX).path[0] = '/'
+ (CCTX).ctx = (CTX);
/**
* @brief Initalize local compilation context using a parsed module.
@@ -81,9 +79,7 @@ struct lysc_ctx {
(CCTX).ctx = (PMOD)->mod->ctx; \
(CCTX).cur_mod = (PMOD)->mod; \
(CCTX).pmod = (PMOD); \
- (CCTX).ext = (EXT); \
- (CCTX).path_len = 1; \
- (CCTX).path[0] = '/'
+ (CCTX).ext = (EXT);
/**
* @brief Structure for unresolved items that may depend on any implemented module data in the dependency set
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index dac3161ac0..738a0a998d 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -852,6 +852,13 @@ lysp_dup_single(struct lysc_ctx *cctx, const struct lysp_node *pnode, ly_bool wi
case LYS_CASE:
((struct lysp_node_case *)dup)->child = ((struct lysp_node_case *)pnode)->child;
break;
+ case LYS_INPUT:
+ case LYS_OUTPUT:
+ ((struct lysp_node_action_inout *)dup)->child = ((struct lysp_node_action_inout *)pnode)->child;
+ break;
+ case LYS_NOTIF:
+ ((struct lysp_node_notif *)dup)->child = ((struct lysp_node_notif *)pnode)->child;
+ break;
default:
break;
}
@@ -1651,12 +1658,17 @@ lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const stru
LY_ERR ret = LY_SUCCESS;
struct lys_module *orig_mod = ctx->cur_mod;
struct lysp_module *orig_pmod = ctx->pmod;
- char orig_path[LYSC_CTX_BUFSIZE];
+ char *orig_path;
+ uint32_t path_used, path_size;
struct lysp_deviate *d;
/* clear path and set modules */
- strcpy(orig_path, ctx->path);
- ctx->path_len = 1;
+ orig_path = ctx->path;
+ path_used = ctx->path_used;
+ path_size = ctx->path_size;
+ ctx->path = NULL;
+ ctx->path_used = 0;
+ ctx->path_size = 0;
ctx->cur_mod = dev_pmod->mod;
ctx->pmod = (struct lysp_module *)dev_pmod;
@@ -1686,8 +1698,10 @@ lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const stru
ctx->cur_mod = orig_mod;
ctx->pmod = orig_pmod;
- strcpy(ctx->path, orig_path);
- ctx->path_len = strlen(ctx->path);
+ free(ctx->path);
+ ctx->path = orig_path;
+ ctx->path_used = path_used;
+ ctx->path_size = path_size;
return ret;
}
@@ -2137,8 +2151,8 @@ lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
LY_ERR ret = LY_SUCCESS;
struct lys_module *orig_mod = ctx->cur_mod;
struct lysp_module *orig_pmod = ctx->pmod;
- uint32_t i;
- char orig_path[LYSC_CTX_BUFSIZE];
+ uint32_t i, path_used, path_size;
+ char *orig_path;
struct lysc_augment *aug;
/* uses augments */
@@ -2163,9 +2177,10 @@ lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
lysc_update_path(ctx, NULL, NULL);
LY_CHECK_GOTO(ret, cleanup);
- /* augment was applied, remove it (index and the whole set may have changed because other augments
- * could have been applied) */
- ly_set_rm(&ctx->uses_augs, aug, NULL);
+ /* augment was applied, remove it (index and the whole set may have changed because other augments could have
+ * been applied, keep the order so that augments from the same module have a deterministic order) */
+ ly_set_contains(&ctx->uses_augs, aug, &i);
+ ly_set_rm_index_ordered(&ctx->uses_augs, i, NULL);
lysc_augment_free(ctx->ctx, aug);
i = 0;
}
@@ -2181,8 +2196,12 @@ lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
}
/* use the path and modules from the augment */
- strcpy(orig_path, ctx->path);
- ctx->path_len = 1;
+ orig_path = ctx->path;
+ path_used = ctx->path_used;
+ path_size = ctx->path_size;
+ ctx->path = NULL;
+ ctx->path_used = 0;
+ ctx->path_size = 0;
ctx->cur_mod = aug->aug_pmod->mod;
ctx->pmod = (struct lysp_module *)aug->aug_pmod;
lysc_update_path(ctx, NULL, "{augment}");
@@ -2190,12 +2209,15 @@ lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
/* apply augment, restore the path */
ret = lys_compile_augment(ctx, aug->aug_p, node);
- strcpy(ctx->path, orig_path);
- ctx->path_len = strlen(ctx->path);
+ free(ctx->path);
+ ctx->path = orig_path;
+ ctx->path_used = path_used;
+ ctx->path_size = path_size;
LY_CHECK_GOTO(ret, cleanup);
/* augment was applied, remove it */
- ly_set_rm(&ctx->augs, aug, NULL);
+ ly_set_contains(&ctx->augs, aug, &i);
+ ly_set_rm_index_ordered(&ctx->augs, i, NULL);
lysc_augment_free(ctx->ctx, aug);
i = 0;
}
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 2e5ec0917a..aa74b311bd 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -1142,7 +1142,7 @@ lys_compile_type_patterns(struct lysc_ctx *ctx, const struct lysp_restr *pattern
LY_ERR rc = LY_SUCCESS;
struct lysc_pattern **pattern;
LY_ARRAY_COUNT_TYPE u;
- uint32_t format = 0;
+ ly_bool format = 0;
/* first check the format of the patterns based on the current parsed module extensions (not compiled yet),
* if not set, assume internal use that always uses XML Schema expressions */
@@ -1935,18 +1935,75 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
return rc;
}
+/**
+ * @brief Check that a compiled type can be reused and shared.
+ *
+ * @param[in] type_p Parsed type.
+ * @param[in] type_c Compiled type.
+ * @param[in] pattern_format Global pattern format.
+ * @return 1 if @p type_c can be shared;
+ * @return 0 otherwise.
+ */
+static ly_bool
+lys_compile_type_share_compiled(const struct lysp_type *type_p, const struct lysc_type *type_c, ly_bool pattern_format)
+{
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysc_type_union *type_un;
+ struct lysc_type_str *type_str = NULL;
+
+ if (!type_c || type_p->flags || type_p->exts) {
+ /* no compiled type to share, special type flags, or extensions */
+ return 0;
+ }
+
+ /* learn whether the type has a leafref, in which case it cannot be shared because it may resolve to a different
+ * real type for every instantiation */
+ if (type_c->basetype == LY_TYPE_LEAFREF) {
+ /* leafref type */
+ return 0;
+ } else if (type_c->basetype == LY_TYPE_UNION) {
+ /* union with a leafref */
+ type_un = (struct lysc_type_union *)type_c;
+ LY_ARRAY_FOR(type_un->types, u) {
+ if (type_un->types[u]->basetype == LY_TYPE_LEAFREF) {
+ return 0;
+ }
+ }
+ }
+
+ /* check for patterns and their format */
+ if (type_c->basetype == LY_TYPE_STRING) {
+ type_str = (struct lysc_type_str *)type_c;
+ } else if (type_c->basetype == LY_TYPE_UNION) {
+ type_un = (struct lysc_type_union *)type_c;
+ LY_ARRAY_FOR(type_un->types, u) {
+ if (type_un->types[u]->basetype == LY_TYPE_STRING) {
+ type_str = (struct lysc_type_str *)type_un->types[u];
+ break;
+ }
+ }
+ }
+ if (!type_str || !type_str->patterns) {
+ return 1;
+ }
+
+ if (pattern_format != type_str->patterns[0]->format) {
+ return 0;
+ }
+ return 1;
+}
+
LY_ERR
lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
const struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
{
LY_ERR ret = LY_SUCCESS;
- ly_bool dummyloops = 0, has_leafref;
+ ly_bool dummyloops = 0, pattern_format;
struct lys_type_item *tctx, *tctx_prev = NULL, *tctx_iter;
LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
struct lysc_type *base = NULL;
- struct lysc_type_union *base_un;
- LY_ARRAY_COUNT_TYPE u;
struct ly_set tpdf_chain = {0};
+ uint32_t u;
uintptr_t plugin_ref = 0;
*type = NULL;
@@ -2007,7 +2064,7 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t
}
/* circular typedef reference detection */
- for (uint32_t u = 0; u < tpdf_chain.count; u++) {
+ for (u = 0; u < tpdf_chain.count; u++) {
/* local part */
tctx_iter = (struct lys_type_item *)tpdf_chain.objs[u];
if (tctx_iter->tpdf == tctx->tpdf) {
@@ -2018,7 +2075,7 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t
goto cleanup;
}
}
- for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
+ for (u = 0; u < ctx->tpdf_chain.count; u++) {
/* global part for unions corner case */
tctx_iter = (struct lys_type_item *)ctx->tpdf_chain.objs[u];
if (tctx_iter->tpdf == tctx->tpdf) {
@@ -2055,18 +2112,25 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t
goto cleanup;
}
+ /* learn the global pattern format to know what types need to be recompiled */
+ pattern_format = lys_compile_type_patterns_has_oc_posix_ext(ctx->pmod);
+
/* get restrictions from the referred typedefs */
- for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
+ for (u = tpdf_chain.count - 1; u + 1 > 0; --u) {
tctx = (struct lys_type_item *)tpdf_chain.objs[u];
/* remember the typedef context for circular check */
ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
LY_CHECK_GOTO(ret, cleanup);
- if (tctx->tpdf->type.compiled) {
- /* already compiled */
+ if (lys_compile_type_share_compiled(&tctx->tpdf->type, tctx->tpdf->type.compiled, pattern_format)) {
+ /* already compiled, reuse */
base = tctx->tpdf->type.compiled;
continue;
+ } else if (tctx->tpdf->type.compiled) {
+ /* cannot reuse, replace the compiled type with our new compiled type */
+ LY_ATOMIC_DEC_BARRIER(tctx->tpdf->type.compiled->refcount);
+ ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = NULL;
}
/* try to find loaded user type plugins */
@@ -2081,8 +2145,8 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t
}
assert(plugin_ref);
- if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !tctx->tpdf->type.flags &&
- !tctx->tpdf->type.exts && (plugin_ref == base->plugin_ref)) {
+ if (lys_compile_type_share_compiled(&tctx->tpdf->type, base, pattern_format) && (u != tpdf_chain.count - 1) &&
+ (plugin_ref == base->plugin_ref)) {
/* no change, reuse the compiled base */
((struct lysp_tpdf *)tctx->tpdf)->type.compiled = base;
LY_ATOMIC_INC_BARRIER(base->refcount);
@@ -2114,25 +2178,8 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t
/* remove the processed typedef contexts from the stack for circular check */
ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
- /* learn whether the type has a leafref, in which case it cannot be shared because it may resolve to a different
- * real type for every instantiation */
- has_leafref = 0;
- if (basetype == LY_TYPE_LEAFREF) {
- /* leafref type */
- has_leafref = 1;
- } else if ((basetype == LY_TYPE_UNION) && base) {
- /* union with a leafref */
- base_un = (struct lysc_type_union *)base;
- LY_ARRAY_FOR(base_un->types, u) {
- if (base_un->types[u]->basetype == LY_TYPE_LEAFREF) {
- has_leafref = 1;
- break;
- }
- }
- }
-
/* process the type definition in leaf */
- if (type_p->flags || type_p->exts || !base || has_leafref) {
+ if (!lys_compile_type_share_compiled(type_p, base, pattern_format)) {
/* leaf type has changes that need to be compiled into the type */
if (base) {
plugin_ref = base->plugin_ref;
@@ -3028,6 +3075,7 @@ lysc_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t node
/* use the current module */
mod = ctx->cur_mod;
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
if (!ctx_node) {
@@ -3285,29 +3333,31 @@ lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc
}
lysc_update_path(ctx, list->module, key->name);
+
/* key must have the same config flag as the list itself */
if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
LOGVAL(ctx->ctx, NULL, LYVE_SEMANTICS, "Key of a configuration list must not be a state leaf.");
- return LY_EVALID;
+ goto key_invalid;
}
if (ctx->pmod->version < LYS_VERSION_1_1) {
/* YANG 1.0 denies key to be of empty type */
if (key->type->basetype == LY_TYPE_EMPTY) {
LOGVAL(ctx->ctx, NULL, LYVE_SEMANTICS,
"List key of the \"empty\" type is allowed only in YANG 1.1 modules.");
- return LY_EVALID;
+ goto key_invalid;
}
} else {
/* when and if-feature are illegal on list keys */
if (key->when) {
LOGVAL(ctx->ctx, NULL, LYVE_SEMANTICS, "List's key must not have any \"when\" statement.");
- return LY_EVALID;
+ goto key_invalid;
}
/* unable to check if-features but compilation would fail if disabled */
}
/* check status */
- LY_CHECK_RET(lysc_check_status(ctx, NULL, list->flags, list->module, list->name, key->flags, key->module, key->name));
+ LY_CHECK_GOTO(lysc_check_status(ctx, NULL, list->flags, list->module, list->name, key->flags, key->module,
+ key->name), key_invalid);
/* ignore default values of the key */
if (key->dflt.str) {
@@ -3386,6 +3436,10 @@ lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc
done:
return ret;
+
+key_invalid:
+ lysc_update_path(ctx, NULL, NULL);
+ return LY_EVALID;
}
/**
@@ -4013,17 +4067,6 @@ lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char
len = r;
}
- if (!len) {
- /* root node path */
- *path = strdup("/");
- if (!*path) {
- len = -1;
- goto cleanup;
- }
-
- len = 1;
- }
-
cleanup:
if (len < 0) {
free(*path);
@@ -4071,9 +4114,10 @@ lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_
LOGMEM(ctx->ctx);
return LY_EMEM;
}
- strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
- ctx->path_len = (uint32_t)len;
- free(path);
+ free(ctx->path);
+ ctx->path = path;
+ ctx->path_used = len;
+ ctx->path_size = ctx->path_used ? ctx->path_used + 1 : 0;
lysc_update_path(ctx, NULL, "{grouping}");
lysc_update_path(ctx, NULL, grp->name);
@@ -4081,8 +4125,10 @@ lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_
lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
- ctx->path_len = 1;
- ctx->path[1] = '\0';
+ free(ctx->path);
+ ctx->path = NULL;
+ ctx->path_used = 0;
+ ctx->path_size = 0;
cleanup:
lysc_node_container_free(ctx->ctx, &fake_container);
@@ -4094,7 +4140,7 @@ LY_ERR
lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t inherited_flags,
struct ly_set *child_set)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
struct lysc_node *node = NULL;
uint32_t prev_opts = ctx->compile_opts;
@@ -4143,7 +4189,8 @@ lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node
LOGVAL(ctx->ctx, NULL, LYVE_SEMANTICS,
"Action \"%s\" is placed inside %s.", pnode->name,
(ctx->compile_opts & LYS_IS_NOTIF) ? "notification" : "another RPC/action");
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_action));
node_compile_spec = lys_compile_node_action;
@@ -4154,26 +4201,32 @@ lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node
LOGVAL(ctx->ctx, NULL, LYVE_SEMANTICS,
"Notification \"%s\" is placed inside %s.", pnode->name,
(ctx->compile_opts & LYS_IS_NOTIF) ? "another notification" : "RPC/action");
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_notif));
node_compile_spec = lys_compile_node_notif;
ctx->compile_opts |= LYS_COMPILE_NOTIFICATION;
break;
case LYS_USES:
- ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, inherited_flags, child_set);
- lysc_update_path(ctx, NULL, NULL);
- lysc_update_path(ctx, NULL, NULL);
- return ret;
+ rc = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, inherited_flags, child_set);
+ goto cleanup;
default:
LOGINT(ctx->ctx);
- return LY_EINT;
+ rc = LY_EINT;
+ goto cleanup;
}
- LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
+ LY_CHECK_ERR_GOTO(!node, LOGMEM(ctx->ctx); rc = LY_EMEM, cleanup);
- ret = lys_compile_node_(ctx, pnode, parent, inherited_flags, node_compile_spec, node, child_set);
+ rc = lys_compile_node_(ctx, pnode, parent, inherited_flags, node_compile_spec, node, child_set);
+cleanup:
ctx->compile_opts = prev_opts;
- lysc_update_path(ctx, NULL, NULL);
- return ret;
+ if (pnode->nodetype != LYS_USES) {
+ lysc_update_path(ctx, NULL, NULL);
+ } else {
+ lysc_update_path(ctx, NULL, NULL);
+ lysc_update_path(ctx, NULL, NULL);
+ }
+ return rc;
}
diff --git a/src/tree.h b/src/tree.h
index 283cea7688..309c6cb1e7 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -237,6 +237,7 @@ typedef enum {
LY_VALUE_SCHEMA_RESOLVED, /**< resolved YANG schema value, prefixes map to module structures directly */
LY_VALUE_XML, /**< XML data value, prefixes map to XML namespace prefixes */
LY_VALUE_JSON, /**< JSON data value, prefixes map to module names */
+ LY_VALUE_CBOR, /**< CBOR data value, prefixes map to module names (same as JSON) */
LY_VALUE_LYB, /**< LYB data binary value, prefix mapping is type-specific (but usually like JSON) */
LY_VALUE_STR_NS /**< any data format value, prefixes map to XML namespace prefixes */
} LY_VALUE_FORMAT;
diff --git a/src/tree_data.c b/src/tree_data.c
index 4447e52a26..30a9ee5d51 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -78,6 +78,9 @@ lyd_parse_get_format(const struct ly_in *in, LYD_FORMAT format)
} else if ((len >= LY_LYB_SUFFIX_LEN + 1) &&
!strncmp(&path[len - LY_LYB_SUFFIX_LEN], LY_LYB_SUFFIX, LY_LYB_SUFFIX_LEN)) {
format = LYD_LYB;
+ } else if ((len >= LY_CBOR_SUFFIX_LEN + 1) &&
+ !strncmp(&path[len - LY_CBOR_SUFFIX_LEN], LY_CBOR_SUFFIX, LY_CBOR_SUFFIX_LEN)) {
+ format = LYD_CBOR;
} /* else still unknown */
}
@@ -131,6 +134,16 @@ lyd_parse(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **f
case LYD_LYB:
r = lyd_parse_lyb(ctx, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed, &lydctx);
break;
+#ifdef ENABLE_CBOR_SUPPORT
+ case LYD_CBOR:
+ r = lyd_parse_cbor(ctx, NULL, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
+ break;
+#else
+ case LYD_CBOR:
+ LOGARG(ctx, format);
+ r = LY_EINVAL;
+ break;
+#endif /* ENABLE_CBOR_SUPPORT */
case LYD_UNKNOWN:
LOGARG(ctx, format);
r = LY_EINVAL;
@@ -206,6 +219,23 @@ lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *
return lyd_parse(ctx, parent, tree, in, format, parse_options, validate_options, NULL);
}
+LIBYANG_API_DEF LY_ERR
+lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, uint32_t data_len, LYD_FORMAT format,
+ uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
+{
+ LY_ERR ret;
+ struct ly_in *in;
+
+ LY_CHECK_RET(ly_in_new_memory(data, &in));
+ in->length = data_len;
+ in->bounded = 1;
+
+ ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
+
+ ly_in_free(in, 0);
+ return ret;
+}
+
LIBYANG_API_DEF LY_ERR
lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, uint32_t parse_options,
uint32_t validate_options, struct lyd_node **tree)
@@ -460,6 +490,16 @@ lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in
case LYD_LYB:
rc = lyd_parse_lyb(ctx, parent, &first, in, parse_options, val_opts, int_opts, &parsed, &lydctx);
break;
+#ifdef ENABLE_CBOR_SUPPORT
+ case LYD_CBOR:
+ rc = lyd_parse_cbor(ctx, NULL, parent, &first, in, parse_options, val_opts, int_opts, &parsed, NULL, &lydctx);
+ break;
+#else
+ case LYD_CBOR:
+ LOGARG(ctx, format);
+ rc = LY_EINVAL;
+ break;
+#endif /* ENABLE_CBOR_SUPPORT */
case LYD_UNKNOWN:
LOGARG(ctx, format);
rc = LY_EINVAL;
@@ -2894,10 +2934,7 @@ lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *bufl
len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
- quot = '\'';
- if (strchr(val, '\'')) {
- quot = '"';
- }
+ LY_CHECK_RET(ly_val_get_quot(LYD_CTX(node), val, "));
*bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
}
@@ -2912,7 +2949,7 @@ lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *bufl
* @param[in,out] buflen Current buffer length.
* @param[in,out] bufused Current number of characters used in @p buffer.
* @param[in] is_static Whether buffer is static or can be reallocated.
- * @return LY_ERR
+ * @return LY_ERR value.
*/
static LY_ERR
lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
@@ -2925,10 +2962,7 @@ lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *
len = 4 + strlen(val) + 2; /* "[.='" + val + "']" */
LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
- quot = '\'';
- if (strchr(val, '\'')) {
- quot = '"';
- }
+ LY_CHECK_RET(ly_val_get_quot(LYD_CTX(node), val, "));
*bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
return LY_SUCCESS;
@@ -3013,7 +3047,7 @@ lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size
len = 1 + (mod ? strlen(mod->name) + 1 : 0) + (iter->schema ? strlen(iter->schema->name) :
strlen(((struct lyd_node_opaq *)iter)->name.name));
rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
- if (rc != LY_SUCCESS) {
+ if (rc) {
break;
}
@@ -3046,7 +3080,7 @@ lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size
break;
}
}
- if (rc != LY_SUCCESS) {
+ if (rc) {
break;
}
@@ -3055,6 +3089,10 @@ lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size
break;
}
+ if (rc && !is_static) {
+ free(buffer);
+ buffer = NULL;
+ }
return buffer;
}
diff --git a/src/tree_data.h b/src/tree_data.h
index badbd77e80..946c0afb8d 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -536,7 +536,8 @@ typedef enum {
LYD_UNKNOWN = 0, /**< unknown data format, invalid value */
LYD_XML, /**< XML instance data format */
LYD_JSON, /**< JSON instance data format */
- LYD_LYB /**< LYB instance data format */
+ LYD_LYB, /**< LYB instance data format */
+ LYD_CBOR /**< CBOR instance data format */
} LYD_FORMAT;
/** @} */
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index 29ac333e15..3f22f22bdf 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -317,6 +317,7 @@ lyd_owner_module(const struct lyd_node *node)
return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
}
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
if (opaq->name.module_name) {
return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
@@ -351,6 +352,7 @@ lyd_node_module(const struct lyd_node *node)
return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
}
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
if (opaq->name.module_name) {
return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
@@ -895,6 +897,7 @@ lyd_parse_opaq_error(const struct lyd_node *node)
mod = sparent->module;
}
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
if (!sparent || strcmp(opaq->name.module_name, sparent->module->name)) {
@@ -1243,6 +1246,7 @@ ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
break;
case LY_VALUE_CANON:
case LY_VALUE_SCHEMA:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
break;
@@ -1302,6 +1306,7 @@ ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void
}
break;
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
assert(!prefix_data);
@@ -1427,6 +1432,7 @@ ly_store_prefix_data(const struct ly_ctx *ctx, const void *value, uint32_t value
break;
case LY_VALUE_CANON:
case LY_VALUE_SCHEMA_RESOLVED:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
if (!*prefix_data_p) {
@@ -1457,6 +1463,8 @@ ly_format2str(LY_VALUE_FORMAT format)
return "schema stored mapping";
case LY_VALUE_XML:
return "XML prefixes";
+ case LY_VALUE_CBOR:
+ return "CBOR module names";
case LY_VALUE_JSON:
return "JSON module names";
case LY_VALUE_LYB:
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index da46df22f5..63d6882898 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -33,6 +33,8 @@ struct lysc_module;
#define LY_JSON_SUFFIX_LEN 5
#define LY_LYB_SUFFIX ".lyb"
#define LY_LYB_SUFFIX_LEN 4
+#define LY_CBOR_SUFFIX ".cbor"
+#define LY_CBOR_SUFFIX_LEN 5
/**
* @brief Internal item structure for remembering "used" instances of duplicate node instances.
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index 897ded115f..b2aa67dd77 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -789,7 +789,7 @@ lyd_new_term_raw(struct lyd_node *parent, const struct lys_module *module, const
/* spend the value */
if (value_size > LYD_VALUE_FIXED_MEM_SIZE) {
term->value.dyn_mem = malloc(value_size);
- LY_CHECK_ERR_RET(!term->value.dyn_mem, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_ERR_RET(!term->value.dyn_mem, LOGMEM(ctx); free(term), LY_EMEM);
memcpy(term->value.dyn_mem, value_ptr, value_size);
} else {
memcpy(term->value.fixed_mem, value_ptr, value_size);
@@ -946,6 +946,7 @@ lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, uint32_t option
return LY_ENOTFOUND;
}
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
mod = ly_ctx_get_module_implemented(ctx, attr->name.module_name);
if (!mod) {
@@ -972,6 +973,12 @@ lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name
LY_CHECK_ARG_RET(ctx, parent || ctx, parent || node, name, module_name, !prefix || !strcmp(prefix, module_name), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
+ if (parent && parent->schema && !(parent->schema->nodetype & LYD_NODE_INNER)) {
+ LOGERR(ctx, LY_EINVAL, "Cannot insert into %s node \"%s\".", lys_nodetype2str(parent->schema->nodetype),
+ LYD_NAME(parent));
+ return LY_EINVAL;
+ }
+
if (!ctx) {
ctx = LYD_CTX(parent);
}
@@ -1002,6 +1009,12 @@ lyd_new_opaq2(struct lyd_node *parent, const struct ly_ctx *ctx, const char *nam
LY_CHECK_ARG_RET(ctx, parent || ctx, parent || node, name, module_ns, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
+ if (parent && parent->schema && !(parent->schema->nodetype & LYD_NODE_INNER)) {
+ LOGERR(ctx, LY_EINVAL, "Cannot insert into %s node \"%s\".", lys_nodetype2str(parent->schema->nodetype),
+ LYD_NAME(parent));
+ return LY_EINVAL;
+ }
+
if (!ctx) {
ctx = LYD_CTX(parent);
}
@@ -1543,7 +1556,7 @@ lyd_new_path_check_find_lypath(struct ly_path *path, const char *str_path, const
if (!r) {
/* validate the value and store the canonical value */
r = lyd_value_validate3(schema, value, LYPLG_BITS2BYTES(value_size_bits), format, NULL, LYD_HINT_DATA,
- NULL, 0, NULL, &canon);
+ NULL, 1, NULL, &canon);
LY_CHECK_RET(r && r != LY_EINCOMPLETE, r);
/* store the new predicate so that it is used when searching for this instance */
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 6f3e9273ef..78576479cd 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -219,6 +219,7 @@ ly_resolve_prefix(const struct ly_ctx *ctx, const void *prefix, uint32_t prefix_
case LY_VALUE_CANON:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_CBOR:
mod = ly_json_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
break;
}
@@ -243,6 +244,7 @@ lys_find_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, cons
case LY_VALUE_CANON:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_CBOR:
case LY_VALUE_STR_NS:
/* use context node module (as specified) */
return ctx_node ? ctx_node->module : NULL;
@@ -1530,38 +1532,6 @@ lysp_path_until(const struct lysp_node *node, const struct lysp_node *parent, co
return path;
}
-/**
- * @brief Append a formatted message to a buffer.
- *
- * @param[in,out] buf Buffer to use.
- * @param[in,out] size Size of @p buf.
- * @param[in] format Message format.
- * @param[in] ... Message format arguments.
- * @return LY_ERR value.
- */
-static LY_ERR
-lysp_ext_instance_path_append(char **buf, uint32_t *size, const char *format, ...)
-{
- va_list ap;
- uint32_t len;
-
- /* learn the required length */
- va_start(ap, format);
- len = vsnprintf(*buf ? *buf + *size : NULL, 0, format, ap);
- va_end(ap);
-
- /* realloc */
- *buf = ly_realloc(*buf, (*size) + len + 1);
- LY_CHECK_ERR_RET(!*buf, LOGMEM(NULL), LY_EMEM);
-
- /* print */
- va_start(ap, format);
- *size += vsnprintf(*buf + *size, len + 1, format, ap);
- va_end(ap);
-
- return LY_SUCCESS;
-}
-
/**
* @brief Append the log path of a statement to a string, recursively.
*
@@ -1571,16 +1541,17 @@ lysp_ext_instance_path_append(char **buf, uint32_t *size, const char *format, ..
* @param[in] stmt_p Pointer to the statement structure.
* @param[in] pmod Parsed module to use.
* @param[in,out] buf Buffer to use.
+ * @param[in,out] used Used bytes of @p buf without terminating 0.
* @param[in,out] size Size of @p buf.
* @return LY_ERR value.
*/
static LY_ERR
lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt, LY_ARRAY_COUNT_TYPE stmt_idx,
- const void *stmt_p, const struct lysp_module *pmod, char **buf, uint32_t *size)
+ const void *stmt_p, const struct lysp_module *pmod, char **buf, uint32_t *used, uint32_t *size)
{
- if (*size && ((*buf)[*size - 1] != ':')) {
+ if (*used && ((*buf)[*used - 1] != ':')) {
/* slash after the previous path, if not module name */
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/"));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/"));
}
switch (stmt) {
@@ -1602,30 +1573,31 @@ lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt
case LY_STMT_USES:
*buf = lysp_path_until(stmt_p, NULL, pmod);
LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
- *size = strlen(*buf);
+ *used = strlen(*buf);
+ *size = *used + 1;
break;
case LY_STMT_ARGUMENT:
case LY_STMT_YIN_ELEMENT:
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_EXTENSION, 0, stmt_p, pmod, buf, size));
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_EXTENSION, 0, stmt_p, pmod, buf, used, size));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_BASE: {
const char * const *bases = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), bases[stmt_idx]));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), bases[stmt_idx]));
break;
}
case LY_STMT_BELONGS_TO: {
const struct lysp_submodule *submod = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), submod->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), submod->name));
break;
}
case LY_STMT_BIT:
case LY_STMT_ENUM: {
const struct lysp_type_enum *be = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), be->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), be->name));
break;
}
case LY_STMT_CONFIG:
@@ -1638,12 +1610,12 @@ lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt
case LY_STMT_ORGANIZATION:
case LY_STMT_PREFIX:
case LY_STMT_YANG_VERSION:
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_DEFAULT: {
const struct lysp_qname *qn = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), qn->str));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), qn->str));
break;
}
case LY_STMT_DEVIATE: {
@@ -1651,16 +1623,16 @@ lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt
switch (d->mod) {
case LYS_DEV_NOT_SUPPORTED:
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='not-supported'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='not-supported'}", lyplg_ext_stmt2str(stmt)));
break;
case LYS_DEV_ADD:
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='add'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='add'}", lyplg_ext_stmt2str(stmt)));
break;
case LYS_DEV_DELETE:
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='delete'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='delete'}", lyplg_ext_stmt2str(stmt)));
break;
case LYS_DEV_REPLACE:
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='replace'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='replace'}", lyplg_ext_stmt2str(stmt)));
break;
}
break;
@@ -1668,91 +1640,91 @@ lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt
case LY_STMT_DEVIATION: {
const struct lysp_deviation *dev = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), dev->nodeid));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), dev->nodeid));
break;
}
case LY_STMT_ERROR_APP_TAG:
case LY_STMT_ERROR_MESSAGE:
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{restriction}/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{restriction}/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_EXTENSION: {
const struct lysp_ext *ext = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), ext->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), ext->name));
break;
}
case LY_STMT_EXTENSION_INSTANCE: {
const struct lysp_ext_instance *ext = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{ext-inst='%s'}", ext->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{ext-inst='%s'}", ext->name));
if (ext->argument) {
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/%s", ext->argument));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/%s", ext->argument));
}
break;
}
case LY_STMT_FEATURE: {
const struct lysp_feature *f = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), f->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), f->name));
break;
}
case LY_STMT_FRACTION_DIGITS:
case LY_STMT_PATH:
case LY_STMT_REQUIRE_INSTANCE:
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_TYPE, 0, stmt_p, pmod, buf, size));
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_TYPE, 0, stmt_p, pmod, buf, used, size));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_IDENTITY: {
const struct lysp_ident *id = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), id->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), id->name));
break;
}
case LY_STMT_IF_FEATURE:
case LY_STMT_UNIQUE: {
const struct lysp_qname *qns = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), qns[stmt_idx].str));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), qns[stmt_idx].str));
break;
}
case LY_STMT_IMPORT: {
const struct lysp_import *imp = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), imp->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), imp->name));
break;
}
case LY_STMT_INCLUDE: {
const struct lysp_include *inc = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), inc->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), inc->name));
break;
}
case LY_STMT_KEY:
case LY_STMT_ORDERED_BY:
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_LIST, 0, stmt_p, pmod, buf, size));
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_LIST, 0, stmt_p, pmod, buf, used, size));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_LENGTH:
case LY_STMT_MUST:
case LY_STMT_RANGE: {
const struct lysp_restr *res = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), res->arg.str));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), res->arg.str));
break;
}
case LY_STMT_MODIFIER:
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_PATTERN, 0, stmt_p, pmod, buf, size));
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_PATTERN, 0, stmt_p, pmod, buf, used, size));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_PATTERN: {
const struct lysp_restr *res = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), res->arg.str + 1));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), res->arg.str + 1));
break;
}
case LY_STMT_POSITION:
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_BIT, 0, stmt_p, pmod, buf, size));
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_BIT, 0, stmt_p, pmod, buf, used, size));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_PRESENCE:
case LY_STMT_REFERENCE:
@@ -1760,53 +1732,53 @@ lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt
case LY_STMT_UNITS: {
const char *str = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), str));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), str));
break;
}
case LY_STMT_REFINE: {
const struct lysp_refine *rf = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), rf->nodeid));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), rf->nodeid));
break;
}
case LY_STMT_REVISION: {
const struct lysp_revision *rev = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), rev->date));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), rev->date));
break;
}
case LY_STMT_STATUS: {
const uint16_t *flags = stmt_p;
if (*flags & LYS_STATUS_OBSLT) {
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='obsolete'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='obsolete'}", lyplg_ext_stmt2str(stmt)));
} else if (*flags & LYS_STATUS_DEPRC) {
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='deprecated'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='deprecated'}", lyplg_ext_stmt2str(stmt)));
} else {
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='current'}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='current'}", lyplg_ext_stmt2str(stmt)));
}
break;
}
case LY_STMT_TYPE: {
const struct lysp_type *typ = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), typ->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), typ->name));
break;
}
case LY_STMT_TYPEDEF: {
const struct lysp_tpdf *tpdf = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), tpdf->name));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), tpdf->name));
break;
}
case LY_STMT_VALUE:
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_ENUM, 0, stmt_p, pmod, buf, size));
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_ENUM, 0, stmt_p, pmod, buf, used, size));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "/{%s}", lyplg_ext_stmt2str(stmt)));
break;
case LY_STMT_WHEN: {
const struct lysp_when *wh = stmt_p;
- LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), wh->cond));
+ LY_CHECK_RET(ly_append_str(buf, size, used, "{%s='%s'}", lyplg_ext_stmt2str(stmt), wh->cond));
break;
}
case LY_STMT_NONE:
@@ -1829,27 +1801,27 @@ lysp_ext_instance_path(const struct ly_ctx *ctx, const struct lysp_module *pmod,
char **path)
{
char *buf = NULL;
- uint32_t size = 0;
+ uint32_t used = 0, size = 0;
if (ext->parent_stmt == LY_STMT_MODULE) {
/* module name */
- LY_CHECK_RET(lysp_ext_instance_path_append(&buf, &size, "/%s:", ((struct lysp_module *)ext->parent)->mod->name));
+ LY_CHECK_RET(ly_append_str(&buf, &size, &used, "/%s:", ((struct lysp_module *)ext->parent)->mod->name));
} else if (ext->parent_stmt == LY_STMT_SUBMODULE) {
/* submodule name */
- LY_CHECK_RET(lysp_ext_instance_path_append(&buf, &size, "/%s:", ((struct lysp_submodule *)ext->parent)->name));
+ LY_CHECK_RET(ly_append_str(&buf, &size, &used, "/%s:", ((struct lysp_submodule *)ext->parent)->name));
} else {
/* start with the module name unless a node is parent, which will include its module name */
if (!(ext->parent_stmt & LY_STMT_NODE_MASK)) {
- LY_CHECK_RET(lysp_ext_instance_path_append(&buf, &size, "/%s:", pmod->mod->name));
+ LY_CHECK_RET(ly_append_str(&buf, &size, &used, "/%s:", pmod->mod->name));
}
/* generate path of the parent statement */
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, ext->parent_stmt, ext->parent_stmt_index, ext->parent, pmod,
- &buf, &size));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, ext->parent_stmt, ext->parent_stmt_index, ext->parent,
+ pmod, &buf, &used, &size));
}
/* append the extension instance path */
- LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_EXTENSION_INSTANCE, 0, ext, pmod, &buf, &size));
+ LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_EXTENSION_INSTANCE, 0, ext, pmod, &buf, &used, &size));
*path = buf;
return LY_SUCCESS;
@@ -3196,3 +3168,36 @@ lys_search_localfile(const char * const *searchpaths, ly_bool cwd, const char *n
return ret;
}
+
+LIBYANG_API_DEF LY_ERR
+lys_sid_gen(const struct lys_module *module, uint64_t entry_point, uint64_t size,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file)
+{
+ LY_CHECK_ARG_RET(NULL, module, sid_file, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, module->compiled, module->parsed, size, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, ly_ctx_get_module_implemented(module->ctx, "ietf-sid-file"), LY_ENOTFOUND);
+
+ *sid_file = NULL;
+ return sid_file_gen(module, entry_point, size, status, description, sid_file);
+}
+
+LIBYANG_API_DEF LY_ERR
+lys_sid_update(const struct lys_module *module, const struct lyd_node *prev_sid_file,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file)
+{
+ LY_CHECK_ARG_RET(NULL, module, prev_sid_file, sid_file, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, module->compiled, module->parsed, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, ly_ctx_get_module_implemented(module->ctx, "ietf-sid-file"), LY_ENOTFOUND);
+
+ *sid_file = NULL;
+ return sid_file_update(module, prev_sid_file, status, description, sid_file);
+}
+
+LIBYANG_API_DEF LY_ERR
+lys_sid_range_add(struct lyd_node *sid_file, uint64_t entry_point, uint64_t size)
+{
+ LY_CHECK_ARG_RET(NULL, sid_file, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, size, LY_EINVAL);
+
+ return sid_range_append(sid_file, entry_point, size);
+}
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 8e1f18b9d6..07ff9e46f1 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -2340,6 +2340,86 @@ LIBYANG_API_DECL const char *lys_nodetype2str(uint16_t nodetype);
*/
LIBYANG_API_DECL const char *lyxp_get_expr(const struct lyxp_expr *path);
+/**
+ * @brief Status of a generated .sid file, mirroring the 'sid-file-status' leaf
+ * from ietf-sid-file (RFC 9595, sec. 4).
+ */
+typedef enum {
+ LYS_SID_FILE_UNPUBLISHED = 0, /**< work-in-progress file, items have status 'unstable' */
+ LYS_SID_FILE_PUBLISHED = 1 /**< stable file, does not contain 'unstable' items */
+} LYS_SID_FILE_STATUS;
+
+/**
+ * @brief Generate a .sid file content of a module as an ietf-sid-file data tree.
+ *
+ * @note For complete SID coverage, all features of @p module must be enabled
+ * before calling this function. Schema nodes guarded by `if-feature` that are
+ * not enabled are absent from the compiled tree and will not be collected.
+ *
+ * @param[in] module Implemented module to collect items from. Its context must have the "ietf-sid-file" module implemented.
+ * @param[in] entry_point First SID of the assignment range.
+ * @param[in] size Number of SIDs available in the range, must cover all items.
+ * @param[in] status Status of the SID file (::LYS_SID_FILE_UNPUBLISHED or ::LYS_SID_FILE_PUBLISHED).
+ * When ::LYS_SID_FILE_UNPUBLISHED, every item gets status "unstable"; a published file
+ * contains no "unstable" items.
+ * @param[in] description Optional description string written to the "description" leaf, NULL to auto-generate
+ * "Generated by libyang \, at \".
+ * @param[out] sid_file Generated data tree ("/ietf-sid-file:sid-file"), caller must free with ::lyd_free_all().
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL if @p module is not implemented, @p size is zero or smaller than the number of collected items, @p module or @p sid_file is NULL.
+ * @return LY_ENOTFOUND if "ietf-sid-file" is not implemented in the module's context.
+ * @return LY_ERR on other errors.
+ */
+LIBYANG_API_DECL LY_ERR lys_sid_gen(const struct lys_module *module, uint64_t entry_point, uint64_t size,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file);
+
+/**
+ * @brief Update a .sid file content of a module from a previous .sid file.
+ *
+ * Merges items from the previous .sid file with items collected from the current
+ * compiled schema. Items that still exist keep their previously assigned SIDs and
+ * statuses; new items get the first SID after the highest used SID in each
+ * assignment range; items that no longer exist in the schema are retained with
+ * status "obsolete" (RFC 9595 The sid-file-version is incremented by 1.
+ *
+ * @note For complete SID coverage, all features of @p module must be enabled
+ * before calling this function. Schema nodes guarded by `if-feature` that are
+ * not enabled are absent from the compiled tree and will not be collected.
+ *
+ * @param[in] module Implemented module to collect items from. Its context must have the "ietf-sid-file" module implemented.
+ * @param[in] prev_sid_file Root node of the previous .sid file data tree (parsed from JSON with ::lyd_parse_data_mem).
+ * @param[in] status Status of the SID file (::LYS_SID_FILE_UNPUBLISHED or ::LYS_SID_FILE_PUBLISHED).
+ * When ::LYS_SID_FILE_PUBLISHED, all "unstable" item statuses are stripped (set to the default "stable");
+ * "obsolete" statuses are always preserved.
+ * @param[in] description Optional description string written to the "description" leaf, NULL to auto-generate
+ * "Generated by libyang \, at \".
+ * @param[out] sid_file Generated data tree ("/ietf-sid-file:sid-file"), caller must free with ::lyd_free_all().
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL if @p module is not implemented, or on invalid previous file content (module name mismatch, SID outside any range, no free SID left),
+ * or @p module, @p prev_sid_file, or @p sid_file is NULL.
+ * @return LY_ENOTFOUND if "ietf-sid-file" is not implemented in the module's context.
+ * @return LY_ERR on other errors.
+ */
+LIBYANG_API_DECL LY_ERR lys_sid_update(const struct lys_module *module, const struct lyd_node *prev_sid_file,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file);
+
+/**
+ * @brief Append a new assignment range to an existing .sid file data tree.
+ *
+ * The range is appended directly into @p sid_file (in place).
+ *
+ * @param[in] sid_file Data tree ("/ietf-sid-file:sid-file") to add the range to.
+ * @param[in] entry_point First SID of the new range.
+ * @param[in] size Number of SIDs in the new range, must be non-zero.
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL if @p sid_file is NULL.
+ * @return LY_EINVAL if @p size is zero, @p sid_file does not have the sid-file
+ * root node, the range exceeds the SID data type bounds, the existing ranges
+ * miss required data, or the range overlaps an existing one.
+ * @return LY_ERR on other errors.
+ */
+LIBYANG_API_DECL LY_ERR lys_sid_range_add(struct lyd_node *sid_file, uint64_t entry_point, uint64_t size);
+
/** @} schematree */
#ifdef __cplusplus
diff --git a/src/tree_schema_common.c b/src/tree_schema_common.c
index b98bfa6fd4..2f5207c8c8 100644
--- a/src/tree_schema_common.c
+++ b/src/tree_schema_common.c
@@ -91,7 +91,7 @@ lysp_last_revision(const struct lysp_module *pmod, const struct lysp_revision *r
cmp = strcmp(revs[u].date, revs[u + 1].date);
if (cmp < 0) {
if (ctx) {
- LOGWRN(ctx, "Older revision %s found after a newer revision %s in %s \"%s\".", revs[u].date,
+ LOGWRN(ctx, "Older revision %s found before a newer revision %s in %s \"%s\".", revs[u].date,
revs[u + 1].date, mod_str, name);
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 6216a85161..e36855a0da 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -693,6 +693,7 @@ char *lysc_path_until(const struct lysc_node *node, const struct lysc_node *pare
* LY_VALUE_SCHEMA - const struct ::lysp_module* (module used for resolving imports to prefixes)
* LY_VALUE_SCHEMA_RESOLVED - struct ::lysc_prefix* (sized array of pairs: prefix - module)
* LY_VALUE_XML - struct ::ly_set* (set of all returned modules as struct ::lys_module)
+ * LY_VALUE_CBOR - NULL
* LY_VALUE_JSON - NULL
* LY_VALUE_LYB - NULL
* @return Module prefix to print.
@@ -712,6 +713,7 @@ const char *ly_get_prefix(const struct lys_module *mod, LY_VALUE_FORMAT format,
* LY_VALUE_SCHEMA - const struct lysp_module * (module used for resolving prefixes from imports)
* LY_VALUE_SCHEMA_RESOLVED - struct lyd_value_prefix * (sized array of pairs: prefix - module)
* LY_VALUE_XML - const struct ly_set * (set with defined namespaces stored as ::lyxml_ns)
+ * LY_VALUE_CBOR - NULL
* LY_VALUE_JSON - NULL
* LY_VALUE_LYB - NULL
* @return Resolved prefix module,
@@ -892,4 +894,49 @@ void *ly_ctx_compiled_addr_ht_get(const struct ly_ht *addr_ht, const void *addr,
*/
LY_ERR ly_ctx_compiled_addr_ht_add(struct ly_ht *addr_ht, const void *orig_addr, const void *addr);
+/**
+ * @brief Generate a .sid file data tree. Internal implementation of ::lys_sid_gen, expects arguments already validated.
+ *
+ * @param[in] module Implemented module to collect items from. Its context must have the "ietf-sid-file" module implemented.
+ * @param[in] entry_point First SID of the assignment range.
+ * @param[in] size Number of SIDs available in the range, must cover all items.
+ * @param[in] status Status of the SID file (::LYS_SID_FILE_UNPUBLISHED or ::LYS_SID_FILE_PUBLISHED).
+ * @param[in] description Optional description string written to the "description" leaf, NULL to auto-generate
+ * "Generated by libyang \, at \".
+ * @param[out] sid_file Generated data tree ("/ietf-sid-file:sid-file"), caller must free with ::lyd_free_all().
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL if @p size is smaller than the number of collected items.
+ * @return LY_ERR on other errors.
+ */
+LY_ERR sid_file_gen(const struct lys_module *module, uint64_t entry_point, uint64_t size,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file);
+
+/**
+ * @brief Update a .sid file data tree. Internal implementation of ::lys_sid_update, expects arguments already validated.
+ *
+ * @param[in] module Implemented module to collect items from. Its context must have the "ietf-sid-file" module implemented.
+ * @param[in] prev_sid_file Root node of the previous .sid file data tree.
+ * @param[in] status Status of the SID file (::LYS_SID_FILE_UNPUBLISHED or ::LYS_SID_FILE_PUBLISHED).
+ * @param[in] description Optional description string written to the "description" leaf, NULL to auto-generate
+ * "Generated by libyang \, at \".
+ * @param[out] sid_file Generated data tree ("/ietf-sid-file:sid-file"), caller must free with ::lyd_free_all().
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL on invalid previous file or if the assignment ranges cannot cover all items.
+ * @return LY_ERR on other errors.
+ */
+LY_ERR sid_file_update(const struct lys_module *module, const struct lyd_node *prev_sid_file,
+ LYS_SID_FILE_STATUS status, const char *description, struct lyd_node **sid_file);
+
+/**
+ * @brief Append a new assignment range to a .sid file data tree. Internal implementation of ::lys_sid_range_add, expects arguments already validated.
+ *
+ * @param[in] tree Data tree ("/ietf-sid-file:sid-file") to add the range to.
+ * @param[in] entry_point First SID of the new range.
+ * @param[in] size Number of SIDs in the new range.
+ * @return LY_SUCCESS on success.
+ * @return LY_EINVAL if @p tree is not the sid-file root node, the range exceeds the SID data type bound (2^63-1), or overlaps an already declared range.
+ * @return LY_ERR on other errors.
+ */
+LY_ERR sid_range_append(struct lyd_node *tree, uint64_t entry_point, uint64_t size);
+
#endif /* LY_TREE_SCHEMA_INTERNAL_H_ */
diff --git a/src/validation.c b/src/validation.c
index 5cfdd27c8a..b847f153d2 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -357,20 +357,15 @@ lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, con
}
}
-#ifndef NDEBUG
if (node_when && node_when->count) {
/* remove nested from node_when set */
LYD_TREE_DFS_BEGIN(del, iter) {
if ((del != iter) && ly_set_contains(node_when, iter, &idx)) {
- assert(0 && "Please contact libyang support with the use-case that triggered this assert.");
- // ly_set_rm_index(node_when, idx, NULL);
+ ly_set_rm_index(node_when, idx, NULL);
}
LYD_TREE_DFS_END(del, iter);
}
}
-#else
- (void)node_when;
-#endif
if (node_types && node_types->count) {
/* remove from node_types set */
diff --git a/src/xml.c b/src/xml.c
index fea01247cd..a520303584 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -361,7 +361,7 @@ lyxml_parse_qname(struct lyxml_ctx *xmlctx, const char **prefix, uint32_t *prefi
LY_CHECK_RET(lyxml_parse_identifier(xmlctx, &start, &end));
if (end[0] == ':') {
/* we have prefixed identifier */
- if (end - start > UINT32_MAX) {
+ if (((uint64_t)(end - start)) > UINT32_MAX) {
LOGVAL(xmlctx->ctx, NULL, LYVE_SYNTAX, "XML qualified name prefix too long.");
return LY_EINVAL;
}
@@ -373,7 +373,7 @@ lyxml_parse_qname(struct lyxml_ctx *xmlctx, const char **prefix, uint32_t *prefi
LY_CHECK_RET(lyxml_parse_identifier(xmlctx, &start, &end));
}
- if (end - start > UINT32_MAX) {
+ if (((uint32_t)(end - start)) > UINT32_MAX) {
LOGVAL(xmlctx->ctx, NULL, LYVE_SYNTAX, "XML qualified name too long.");
return LY_EINVAL;
}
@@ -728,7 +728,7 @@ lyxml_open_element(struct lyxml_ctx *xmlctx, const char *prefix, uint32_t prefix
LY_CHECK_RET(ly_set_add(&xmlctx->elements, e, 1, NULL));
if (xmlctx->elements.count > LY_MAX_BLOCK_DEPTH) {
- LOGERR(xmlctx->ctx, LY_EINVAL, "The maximum number of open elements has been exceeded.");
+ LOGERR(xmlctx->ctx, LY_EINVAL, "Maximum number %d of open elements has been exceeded.", LY_MAX_BLOCK_DEPTH);
return LY_EINVAL;
}
diff --git a/src/xpath.c b/src/xpath.c
index a45b96b290..c95b395066 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -239,43 +239,6 @@ str2axis(const char *str, uint32_t str_len)
return 0;
}
-/**
- * @brief Append a string to a dynamic string variable.
- *
- * @param[in,out] str String to use.
- * @param[in,out] size String size.
- * @param[in,out] used String used size excluding terminating zero.
- * @param[in] format Message format.
- * @param[in] ... Message format arguments.
- */
-static void
-print_expr_str(char **str, size_t *size, size_t *used, const char *format, ...)
-{
- int p;
- va_list ap;
-
- va_start(ap, format);
-
- /* try to append the string */
- p = vsnprintf(*str ? *str + *used : NULL, *size - *used, format, ap);
-
- if ((unsigned)p >= *size - *used) {
- /* realloc */
- *str = ly_realloc(*str, *size + p + 1);
- *size += p + 1;
-
- /* restart ap */
- va_end(ap);
- va_start(ap, format);
-
- /* print */
- p = vsnprintf(*str + *used, *size - *used, format, ap);
- }
-
- *used += p;
- va_end(ap);
-}
-
/**
* @brief Print the whole expression @p exp to debug output.
*
@@ -285,8 +248,7 @@ static void
print_expr_struct_debug(const struct lyxp_expr *exp)
{
char *buf = NULL;
- uint32_t i, j;
- size_t size = 0, used = 0;
+ uint32_t i, j, size = 0, used = 0;
if (!exp || (ly_ll < LY_LLDBG)) {
return;
@@ -294,15 +256,15 @@ print_expr_struct_debug(const struct lyxp_expr *exp)
LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
for (i = 0; i < exp->used; ++i) {
- print_expr_str(&buf, &size, &used, "\ttoken %s, in expression \"%.*s\"",
+ ly_append_str(&buf, &size, &used, "\ttoken %s, in expression \"%.*s\"",
lyxp_token2str(exp->tokens[i]), exp->tok_len[i], &exp->expr[exp->tok_pos[i]]);
if (exp->repeat && exp->repeat[i]) {
- print_expr_str(&buf, &size, &used, " (repeat %d", exp->repeat[i][0]);
+ ly_append_str(&buf, &size, &used, " (repeat %d", exp->repeat[i][0]);
for (j = 1; exp->repeat[i][j]; ++j) {
- print_expr_str(&buf, &size, &used, ", %d", exp->repeat[i][j]);
+ ly_append_str(&buf, &size, &used, ", %d", exp->repeat[i][j]);
}
- print_expr_str(&buf, &size, &used, ")");
+ ly_append_str(&buf, &size, &used, ")");
}
LOGDBG(LY_LDGXPATH, buf);
used = 0;
@@ -5750,6 +5712,7 @@ moveto_resolve_module(const char **qname, uint32_t *qname_len, const struct lyxp
mod = set->cur_mod;
break;
case LY_VALUE_CANON:
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
case LY_VALUE_STR_NS:
@@ -6424,6 +6387,7 @@ moveto_scnode_check(const struct lysc_node *node, const struct lysc_node *ctx_sc
/* use current module */
moveto_mod = set->cur_mod;
break;
+ case LY_VALUE_CBOR:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
case LY_VALUE_STR_NS:
@@ -7035,8 +6999,8 @@ moveto_scnode_dfs(struct lyxp_set *set, const struct lysc_node *start, uint32_t
/* TREE DFS */
for (elem = next = start; elem; elem = next) {
- if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
- /* schema-only nodes, skip root */
+ if (elem->nodetype & (LYS_CHOICE | LYS_CASE)) {
+ /* schema-only nodes */
goto next_iter;
}
@@ -7974,7 +7938,7 @@ eval_name_test_try_compile_predicate_append(const struct lyxp_expr *exp, uint32_
/* append the JSON predicate */
*pred = ly_realloc(*pred, *pred_len + 1 + strlen(pred_node->name) + 2 + strlen(set2.val.str) + 3);
LY_CHECK_ERR_GOTO(!*pred, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
- quot = strchr(set2.val.str, '\'') ? '\"' : '\'';
+ LY_CHECK_GOTO(rc = ly_val_get_quot(set->ctx, set2.val.str, "), cleanup);
*pred_len += sprintf(*pred + *pred_len, "[%s=%c%s%c]", pred_node->name, quot, set2.val.str, quot);
cleanup:
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d93fae7152..b92420ed43 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -19,6 +19,9 @@ function(ly_add_utest)
# Set common attributes of all tests
set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${PCRE2_LIBRARIES} ${CMAKE_DL_LIBS})
+ if (CBOR_FOUND)
+ target_link_libraries(${TEST_NAME} ${CBOR_LIBRARY})
+ endif()
if (NOT WIN32)
target_link_libraries(${TEST_NAME} m)
else()
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
index 99906166b1..d14e444e7e 100644
--- a/tests/fuzz/CMakeLists.txt
+++ b/tests/fuzz/CMakeLists.txt
@@ -1,5 +1,5 @@
if(ENABLE_FUZZ_TARGETS)
- set(fuzz_targets lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json yang_parse_module)
+ set(fuzz_targets lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json lyd_parse_lyb lyd_parse_schema_mount_xml yang_parse_module)
if(FUZZER STREQUAL "AFL")
foreach(target_name IN LISTS fuzz_targets)
@@ -9,15 +9,15 @@ if(ENABLE_FUZZ_TARGETS)
else()
foreach(target_name IN LISTS fuzz_targets)
add_executable(${target_name}_fuzz_harness ${target_name}.c)
- set_source_files_properties(${target_name}.c PROPERTIES COMPILE_FLAGS "-fsanitize=fuzzer")
- target_link_libraries(${target_name}_fuzz_harness yang "-fsanitize=fuzzer")
+ set_source_files_properties(${target_name}.c PROPERTIES COMPILE_FLAGS "-fsanitize=fuzzer,address,undefined")
+ target_link_libraries(${target_name}_fuzz_harness yang "-fsanitize=fuzzer,address,undefined")
endforeach()
endif()
endif()
if(ENABLE_TESTS)
add_executable(fuzz_regression_test fuzz_regression_test.c)
- set(fuzz_regression_tests lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json)
+ set(fuzz_regression_tests lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json lyd_parse_schema_mount_xml)
foreach(target_name IN LISTS fuzz_regression_tests)
file(COPY ${CMAKE_SOURCE_DIR}/tests/fuzz/corpus/${target_name} DESTINATION ${CMAKE_BINARY_DIR}/tests/fuzz/)
add_executable(regress_fuzz_${target_name} ${target_name}.c main.c)
diff --git a/tests/fuzz/corpus/lyd_parse_schema_mount_xml/valid-mounted-leaf b/tests/fuzz/corpus/lyd_parse_schema_mount_xml/valid-mounted-leaf
new file mode 100644
index 0000000000..0095436052
--- /dev/null
+++ b/tests/fuzz/corpus/lyd_parse_schema_mount_xml/valid-mounted-leaf
@@ -0,0 +1 @@
+1
diff --git a/tests/fuzz/lyd_parse_lyb.c b/tests/fuzz/lyd_parse_lyb.c
new file mode 100644
index 0000000000..2d537ee6c6
--- /dev/null
+++ b/tests/fuzz/lyd_parse_lyb.c
@@ -0,0 +1,39 @@
+#include
+#include
+
+#include "libyang.h"
+#include "tests_config.h"
+
+int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
+{
+ struct ly_ctx *ctx = NULL;
+ struct lyd_node *tree = NULL;
+ static bool log = false;
+ const char *schema =
+ "module fuzz-lyb {namespace urn:tests:fuzz-lyb;prefix fl;"
+ "container c {leaf s {type string;} leaf u16 {type uint16;}"
+ "leaf-list bits {type bits {bit zero; bit one;}}}}";
+
+ if (!log) {
+ ly_log_options(0);
+ log = true;
+ }
+
+ if (ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx) != LY_SUCCESS) {
+ return 0;
+ }
+
+ if (lys_parse_mem(ctx, schema, LYS_IN_YANG, NULL) != LY_SUCCESS) {
+ goto cleanup;
+ }
+
+ if (len <= UINT32_MAX) {
+ lyd_parse_data_mem_len(ctx, (const char *)buf, (uint32_t)len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT,
+ &tree);
+ }
+
+cleanup:
+ lyd_free_all(tree);
+ ly_ctx_destroy(ctx);
+ return 0;
+}
diff --git a/tests/fuzz/lyd_parse_mem_json.c b/tests/fuzz/lyd_parse_mem_json.c
index c2f3e98136..496cda8684 100644
--- a/tests/fuzz/lyd_parse_mem_json.c
+++ b/tests/fuzz/lyd_parse_mem_json.c
@@ -3,6 +3,7 @@
#include
#include "libyang.h"
+#include "tests_config.h"
int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
@@ -60,10 +61,9 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
log = true;
}
- err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
+ err = ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx);
if (err != LY_SUCCESS) {
- fprintf(stderr, "Failed to create context\n");
- exit(EXIT_FAILURE);
+ return 0;
}
lys_parse_mem(ctx, schema_a, LYS_IN_YANG, NULL);
@@ -71,12 +71,14 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
data = malloc(len + 1);
if (data == NULL) {
- return 0;
+ goto cleanup;
}
memcpy(data, buf, len);
data[len] = 0;
lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree);
+
+cleanup:
lyd_free_all(tree);
ly_ctx_destroy(ctx);
diff --git a/tests/fuzz/lyd_parse_mem_xml.c b/tests/fuzz/lyd_parse_mem_xml.c
index e317fde476..e74a34d8db 100644
--- a/tests/fuzz/lyd_parse_mem_xml.c
+++ b/tests/fuzz/lyd_parse_mem_xml.c
@@ -3,6 +3,7 @@
#include
#include "libyang.h"
+#include "tests_config.h"
int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
@@ -60,10 +61,9 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
log = true;
}
- err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
+ err = ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx);
if (err != LY_SUCCESS) {
- fprintf(stderr, "Failed to create context\n");
- exit(EXIT_FAILURE);
+ return 0;
}
lys_parse_mem(ctx, schema_a, LYS_IN_YANG, NULL);
@@ -71,12 +71,14 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
data = malloc(len + 1);
if (data == NULL) {
- return 0;
+ goto cleanup;
}
memcpy(data, buf, len);
data[len] = 0;
lyd_parse_data_mem(ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree);
+
+cleanup:
lyd_free_all(tree);
ly_ctx_destroy(ctx);
diff --git a/tests/fuzz/lyd_parse_schema_mount_xml.c b/tests/fuzz/lyd_parse_schema_mount_xml.c
new file mode 100644
index 0000000000..4461c2ca84
--- /dev/null
+++ b/tests/fuzz/lyd_parse_schema_mount_xml.c
@@ -0,0 +1,171 @@
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include "libyang.h"
+#include "tests_config.h"
+
+static const char mounted_module[] =
+ "module fuzz-sm-leaf {"
+ "namespace \"urn:tests:fuzz-sm-leaf\";"
+ "prefix fsl;"
+ "leaf lfl {type uint16;}"
+ "leaf txt {type string;}"
+ "}";
+
+static const char mount_module[] =
+ "module fuzz-sm {"
+ "yang-version 1.1;"
+ "namespace \"urn:tests:fuzz-sm\";"
+ "prefix fsm;"
+ "import ietf-yang-schema-mount {prefix sm;}"
+ "container root {sm:mount-point \"root\";}"
+ "}";
+
+static const char ext_data_xml[] =
+ ""
+ "fuzz-setfuzz-sm-leaf"
+ "urn:tests:fuzz-sm-leaf"
+ "1"
+ ""
+ "1"
+ ""
+ "fuzz-sm"
+ "";
+
+static const char mount_module_dir_template[] = "/tmp/libyang-sm-fuzz.XXXXXX";
+static char mount_module_dir[sizeof mount_module_dir_template];
+static ly_bool mount_module_dir_ready;
+
+static void
+remove_mount_module_dir(void)
+{
+ char path[sizeof mount_module_dir + sizeof "/fuzz-sm-leaf.yang"];
+
+ if (!mount_module_dir_ready) {
+ return;
+ }
+
+ snprintf(path, sizeof path, "%s/fuzz-sm-leaf.yang", mount_module_dir);
+ unlink(path);
+ rmdir(mount_module_dir);
+ mount_module_dir[0] = 0;
+ mount_module_dir_ready = 0;
+}
+
+static LY_ERR
+prepare_mount_module_dir(void)
+{
+ char path[sizeof mount_module_dir + sizeof "/fuzz-sm-leaf.yang"];
+ FILE *f;
+
+ if (mount_module_dir_ready) {
+ return LY_SUCCESS;
+ }
+
+ memcpy(mount_module_dir, mount_module_dir_template, sizeof mount_module_dir);
+ if (!mkdtemp(mount_module_dir)) {
+ mount_module_dir[0] = 0;
+ return LY_ESYS;
+ }
+ mount_module_dir_ready = 1;
+ atexit(remove_mount_module_dir);
+
+ snprintf(path, sizeof path, "%s/fuzz-sm-leaf.yang", mount_module_dir);
+ f = fopen(path, "w");
+ if (!f) {
+ remove_mount_module_dir();
+ return LY_ESYS;
+ }
+
+ if (fputs(mounted_module, f) == EOF) {
+ fclose(f);
+ remove_mount_module_dir();
+ return LY_ESYS;
+ }
+ if (fclose(f) == EOF) {
+ remove_mount_module_dir();
+ return LY_ESYS;
+ }
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR
+fuzz_ext_data_clb(const struct lysc_ext_instance *ext, const struct lyd_node *parent, void *user_data,
+ void **ext_data, ly_bool *ext_data_free)
+{
+ struct lyd_node *data = NULL;
+ static ly_bool recursive_call;
+ LY_ERR ret = LY_SUCCESS;
+
+ (void)ext;
+ (void)parent;
+
+ *ext_data = NULL;
+ *ext_data_free = 0;
+
+ if (recursive_call) {
+ return LY_SUCCESS;
+ }
+
+ recursive_call = 1;
+ ret = lyd_parse_data_mem(user_data, ext_data_xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &data);
+ recursive_call = 0;
+ if (ret) {
+ lyd_free_all(data);
+ return ret;
+ }
+
+ *ext_data = data;
+ *ext_data_free = 1;
+ return LY_SUCCESS;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
+{
+ struct ly_ctx *ctx = NULL;
+ struct lyd_node *tree = NULL;
+ char *data = NULL;
+ static bool log = false;
+
+ if (!log) {
+ ly_log_options(0);
+ log = true;
+ }
+
+ if (prepare_mount_module_dir() != LY_SUCCESS) {
+ return 0;
+ }
+
+ if (ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx) != LY_SUCCESS) {
+ return 0;
+ }
+ if (ly_ctx_set_searchdir(ctx, mount_module_dir) != LY_SUCCESS) {
+ goto cleanup;
+ }
+ if (lys_parse_mem(ctx, mount_module, LYS_IN_YANG, NULL) != LY_SUCCESS) {
+ goto cleanup;
+ }
+
+ ly_ctx_set_ext_data_clb(ctx, fuzz_ext_data_clb, ctx);
+
+ data = malloc(len + 1);
+ if (!data) {
+ goto cleanup;
+ }
+ memcpy(data, buf, len);
+ data[len] = 0;
+
+ lyd_parse_data_mem(ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, &tree);
+
+cleanup:
+ lyd_free_all(tree);
+ free(data);
+ ly_ctx_destroy(ctx);
+ return 0;
+}
diff --git a/tests/fuzz/lys_parse_mem.c b/tests/fuzz/lys_parse_mem.c
index 6f8d87b407..55846949d8 100644
--- a/tests/fuzz/lys_parse_mem.c
+++ b/tests/fuzz/lys_parse_mem.c
@@ -3,6 +3,7 @@
#include
#include "libyang.h"
+#include "tests_config.h"
int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
@@ -16,14 +17,14 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
log = true;
}
- err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
+ err = ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx);
if (err != LY_SUCCESS) {
- fprintf(stderr, "Failed to create context\n");
- exit(EXIT_FAILURE);
+ return 0;
}
data = malloc(len + 1);
if (data == NULL) {
+ ly_ctx_destroy(ctx);
return 0;
}
diff --git a/tests/fuzz/yang_parse_module.c b/tests/fuzz/yang_parse_module.c
index e9fbe8b428..bc47994416 100644
--- a/tests/fuzz/yang_parse_module.c
+++ b/tests/fuzz/yang_parse_module.c
@@ -3,6 +3,7 @@
#include
#include "libyang.h"
+#include "tests_config.h"
int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
@@ -17,7 +18,7 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
log = true;
}
- err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
+ err = ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx);
if (err != LY_SUCCESS) {
fprintf(stderr, "Failed to create new context\n");
return 0;
@@ -25,7 +26,7 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
data = malloc(len + 1);
if (data == NULL) {
- fprintf(stderr, "Out of memory\n");
+ ly_ctx_destroy(ctx);
return 0;
}
memcpy(data, buf, len);
diff --git a/tests/modules/yang/cbor-test.yang b/tests/modules/yang/cbor-test.yang
new file mode 100644
index 0000000000..09f5237635
--- /dev/null
+++ b/tests/modules/yang/cbor-test.yang
@@ -0,0 +1,263 @@
+module cbor-test {
+ yang-version 1.1;
+ namespace "urn:cbor:test";
+ prefix ct;
+
+ import ietf-yang-schema-mount {
+ prefix yangmnt;
+ }
+
+ revision 2026-07-01;
+
+ identity iface;
+ identity ethernet {
+ base iface;
+ }
+
+ container cont-root {
+ leaf lf-root-str {
+ type string;
+ }
+
+ container services {
+ yangmnt:mount-point "services";
+ }
+ }
+
+ /* ===== Basic scalar types ===== */
+
+ leaf lf-str {
+ type string;
+ }
+
+ leaf lf-bool {
+ type boolean;
+ }
+
+ leaf lf-empty {
+ type empty;
+ }
+
+ leaf lf-bin {
+ type binary;
+ }
+
+ leaf lf-dec64 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ /* ===== Signed integers ===== */
+
+ leaf lf-intg8 {
+ type int8;
+ }
+
+ leaf lf-intg16 {
+ type int16;
+ }
+
+ leaf lf-intg32 {
+ type int32;
+ }
+
+ leaf lf-intg64 {
+ type int64;
+ }
+
+ /* ===== Unsigned integers ===== */
+
+ leaf lf-uintg8 {
+ type uint8;
+ }
+
+ leaf lf-uintg16 {
+ type uint16;
+ }
+
+ leaf lf-uintg32 {
+ type uint32;
+ }
+
+ leaf lf-uintg64 {
+ type uint64;
+ }
+
+ /* ===== Complex built-in types ===== */
+
+ leaf lf-enum {
+ type enumeration {
+ enum red;
+ enum green;
+ enum blue;
+ }
+ }
+
+ leaf lf-bits {
+ type bits {
+ bit up;
+ bit running;
+ bit testing;
+ }
+ }
+
+ leaf lf-idenref {
+ type identityref {
+ base iface;
+ }
+ }
+
+ leaf lf-inst-id {
+ type instance-identifier;
+ }
+
+ leaf lf-union {
+ type union {
+ type uint32;
+ type string;
+ type boolean;
+ }
+ }
+
+ leaf lf-lfref {
+ type leafref {
+ path "../lf-str";
+ }
+ }
+
+ /* ===== Leaf-lists ===== */
+
+ leaf-list ll-str {
+ type string;
+ }
+
+ leaf-list ll-intg32 {
+ type int32;
+ }
+
+ /* ===== Presence container ===== */
+
+ container cont-presence {
+ presence "Presence container.";
+
+ leaf lf-def-str {
+ type string;
+ default "abc";
+ }
+ }
+
+ /* ===== List ===== */
+
+ list list-user {
+ key "key-id";
+
+ leaf key-id {
+ type uint32;
+ }
+
+ leaf lf-name {
+ type string;
+ }
+ }
+
+ /* ===== Nested lists / leaf-lists =====
+ * Regression coverage for the CBOR printer: a leaf-list and a list
+ * nested inside another list. Printing such data used to crash because
+ * the printer kept only a single open-array pointer shared across all
+ * nesting levels.
+ */
+
+ list list-nested {
+ key "id";
+
+ leaf id {
+ type string;
+ }
+
+ leaf-list tags {
+ type string;
+ }
+
+ list inner {
+ key "iid";
+
+ leaf iid {
+ type uint32;
+ }
+
+ leaf-list vals {
+ type int32;
+ }
+ }
+ }
+
+ /* ===== Choice / Case ===== */
+
+ choice choice-transport {
+
+ case case-tcp {
+
+ leaf lf-tcp-port {
+ type uint16;
+ }
+ }
+
+ case case-unix {
+
+ leaf lf-unix-socket {
+ type string;
+ }
+ }
+ }
+
+ /* ===== Anydata / Anyxml ===== */
+
+ anydata anydata-payload;
+
+ anyxml anyxml-payload;
+
+ /* ===== RPC ===== */
+
+ rpc rpc-reset {
+
+ input {
+
+ leaf lf1 {
+ type boolean;
+ }
+ }
+
+ output {
+
+ leaf lf2 {
+ type string;
+ }
+ }
+ }
+
+ /* ===== Notification ===== */
+
+ notification notif-alarm {
+
+ leaf lf-severity {
+ type enumeration {
+ enum info;
+ enum warning;
+ enum critical;
+ }
+ }
+
+ leaf lf-message {
+ type string;
+ }
+ }
+
+ /* ===== Augment ===== */
+
+ augment "/ct:cont-root" {
+ leaf lf-augmented-str {
+ type string;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/perf/CMakeLists.txt b/tests/perf/CMakeLists.txt
index 9e2047b2c5..a63f1d5d65 100644
--- a/tests/perf/CMakeLists.txt
+++ b/tests/perf/CMakeLists.txt
@@ -6,6 +6,10 @@ set(format_sources
add_executable(ly_perf ${CMAKE_CURRENT_SOURCE_DIR}/perf.c $)
set_target_properties(ly_perf PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(ly_perf ${CMAKE_THREAD_LIBS_INIT} ${PCRE2_LIBRARIES} ${CMAKE_DL_LIBS})
+if (CBOR_FOUND)
+ target_link_libraries(ly_perf ${CBOR_LIBRARY})
+endif()
+
if(XXHASH_FOUND)
target_link_libraries(ly_perf ${XXHASH_LIBRARY})
endif()
diff --git a/tests/perf/perf.c b/tests/perf/perf.c
index 01b785e8f2..c3c43085ed 100644
--- a/tests/perf/perf.c
+++ b/tests/perf/perf.c
@@ -875,7 +875,7 @@ main(int argc, char **argv)
(tries > 1) ? "times" : "time");
/* create context */
- if ((ret = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx))) {
+ if ((ret = ly_ctx_new(TESTS_SRC "/../modules", 0, &ctx))) {
goto cleanup;
}
if ((ret = ly_ctx_set_searchdir(ctx, TESTS_SRC "/perf"))) {
diff --git a/tests/style/CMakeLists.txt b/tests/style/CMakeLists.txt
index cf7c97b883..243afb9dab 100644
--- a/tests/style/CMakeLists.txt
+++ b/tests/style/CMakeLists.txt
@@ -9,6 +9,10 @@ endif()
add_executable(cpp_compat cpp_compat.c $)
target_include_directories(cpp_compat BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cpp_compat ${CMAKE_THREAD_LIBS_INIT} ${PCRE2_LIBRARIES} ${CMAKE_DL_LIBS} m)
+if (CBOR_FOUND)
+ target_link_libraries(cpp_compat ${CBOR_LIBRARY})
+endif()
+
if(XXHASH_FOUND)
target_link_libraries(cpp_compat ${XXHASH_LIBRARY})
endif()
diff --git a/tests/tests_config.h.in b/tests/tests_config.h.in
index 119fb35a64..8cbc30538a 100644
--- a/tests/tests_config.h.in
+++ b/tests/tests_config.h.in
@@ -1,9 +1,10 @@
/**
* @file tests_config.h
* @author Radek Krejci
+ * @author Michal Vasko
* @brief cmocka tests configuration header.
*
- * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2026 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.
diff --git a/tests/utests/CMakeLists.txt b/tests/utests/CMakeLists.txt
index 37ae7296c9..70ba43293b 100644
--- a/tests/utests/CMakeLists.txt
+++ b/tests/utests/CMakeLists.txt
@@ -59,6 +59,7 @@ ly_add_utest(NAME yang SOURCES schema/test_yang.c)
ly_add_utest(NAME yin SOURCES schema/test_yin.c)
ly_add_utest(NAME tree_schema_compile SOURCES schema/test_tree_schema_compile.c)
ly_add_utest(NAME printer_tree SOURCES schema/test_printer_tree.c)
+ly_add_utest(NAME printer_sid SOURCES schema/test_printer_sid.c)
ly_add_utest(NAME tree_data SOURCES data/test_tree_data.c)
ly_add_utest(NAME tree_data_sorted SOURCES data/test_tree_data_sorted.c)
@@ -71,6 +72,9 @@ ly_add_utest(NAME lyb SOURCES data/test_lyb.c)
ly_add_utest(NAME validation SOURCES data/test_validation.c)
ly_add_utest(NAME merge SOURCES data/test_merge.c)
ly_add_utest(NAME diff SOURCES data/test_diff.c)
+if(CBOR_FOUND)
+ ly_add_utest(NAME cbor SOURCES data/test_cbor.c)
+endif()
ly_add_utest(NAME metadata SOURCES extensions/test_metadata.c)
ly_add_utest(NAME nacm SOURCES extensions/test_nacm.c)
diff --git a/tests/utests/basic/test_common.c b/tests/utests/basic/test_common.c
index 6e366c5c3b..ef119ad2d9 100644
--- a/tests/utests/basic/test_common.c
+++ b/tests/utests/basic/test_common.c
@@ -14,390 +14,361 @@
#define _UTEST_MAIN_
#include "utests.h"
-#include "ly_common.h"
-
static void
-test_utf8(void **UNUSED(state))
+test_utf8(void **state)
{
- char buf[5] = {0};
- const char *str = buf;
- unsigned int c;
- uint32_t len;
+ int target_idx = 59;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ /* array coresponds to the following YANG module: module test { namespace "urn:test"; prefix t; description "XXX"; } */
+ char test_yang[] = {
+ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x7b, 0x20,
+ 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x20,
+ 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x74, 0x3b, 0x20,
+ 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x22,
+ 0x58, 0x58, 0x58, 0x58,
+ 0x22, 0x3b, 0x20,
+ 0x7d, 0x00
+ };
+
+ lys_parse_mem(ctx, test_yang, LYS_IN_YANG, NULL);
/* test invalid UTF-8 characters in lyxml_getutf8
- * - https://en.wikipedia.org/wiki/UTF-8 */
- buf[0] = (char)0x04;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
- buf[0] = (char)0x80;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
-
- buf[0] = (char)0xc0;
- buf[1] = (char)0x00;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
- buf[1] = (char)0x80;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
-
- buf[0] = (char)0xe0;
- buf[1] = (char)0x00;
- buf[2] = (char)0x80;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
- buf[1] = (char)0x80;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
-
- buf[0] = (char)0xf0;
- buf[1] = (char)0x00;
- buf[2] = (char)0x80;
- buf[3] = (char)0x80;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
- buf[1] = (char)0x80;
- assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
+ * - https://en.wikipedia.org/wiki/UTF-8 */
+ test_yang[target_idx] = (char)0x04;
+
+ /* invalid values */
+ assert_int_equal(LY_EVALID, lys_parse_mem(ctx, test_yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
+
+ test_yang[target_idx] = (char)0xc0;
+ test_yang[target_idx + 1] = (char)0x20;
+ assert_int_equal(LY_EVALID, lys_parse_mem(ctx, test_yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
+
+ test_yang[target_idx + 1] = (char)0x80;
+ assert_int_equal(LY_EVALID, lys_parse_mem(ctx, test_yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
+
+ test_yang[target_idx] = (char)0xe0;
+ test_yang[target_idx + 1] = (char)0x20;
+ test_yang[target_idx + 2] = (char)0x80;
+ assert_int_equal(LY_EVALID, lys_parse_mem(ctx, test_yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
+
+ test_yang[target_idx] = (char)0xf0;
+ test_yang[target_idx + 1] = (char)0x20;
+ test_yang[target_idx + 2] = (char)0x80;
+ test_yang[target_idx + 3] = (char)0x80;
+ assert_int_equal(LY_EVALID, lys_parse_mem(ctx, test_yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
}
static void
-test_parse_int(void **UNUSED(state))
+test_parse_int(void **state)
{
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lys_module *mod = NULL;
+ struct lyd_node *node = NULL;
const char *str;
- int64_t i = 500;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf l {"
+ " type int8;"
+ " }"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, &mod));
+
+ /* correct value */
str = "10";
- assert_int_equal(LY_SUCCESS, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
- assert_int_equal(i, 10);
+ assert_int_equal(LY_SUCCESS, lyd_new_term(NULL, mod, "l", str, 0, &node));
+ assert_string_equal("10", lyd_get_value(node));
/* leading zeros are allowed, trailing whitespaces are allowed */
str = "000\n\t ";
- assert_int_equal(LY_SUCCESS, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
- assert_int_equal(i, 0);
+ assert_int_equal(LY_SUCCESS, lyd_change_term(node, str));
+ assert_string_equal("0", lyd_get_value(node));
/* negative value */
str = "-10";
- assert_int_equal(LY_SUCCESS, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
- assert_int_equal(i, -10);
-
- /* non-NULL terminated string */
- str = "+5sometext";
- assert_int_equal(LY_SUCCESS, ly_parse_int(str, 2, -10, 10, 10, &i));
- assert_int_equal(i, 5);
+ assert_int_equal(LY_SUCCESS, lyd_change_term(node, str));
+ assert_string_equal("-10", lyd_get_value(node));
/* out of bounds value */
- str = "11";
- assert_int_equal(LY_EDENIED, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
- str = "-11";
- assert_int_equal(LY_EDENIED, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
+ str = "128";
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
+
+ str = "-129";
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
/* NaN */
str = "zero";
- assert_int_equal(LY_EVALID, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
/* mixing number with text */
str = "10zero";
- assert_int_equal(LY_EVALID, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
str = "10 zero";
- assert_int_equal(LY_EVALID, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
+
+ lyd_free_all(node);
}
static void
-test_parse_uint(void **UNUSED(state))
+test_parse_uint(void **state)
{
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lys_module *mod = NULL;
+ struct lyd_node *node = NULL;
const char *str;
- uint64_t u = 500;
-
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf l {"
+ " type uint8;"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, &mod));
+ /* correct value */
str = "10";
- assert_int_equal(LY_SUCCESS, ly_parse_uint(str, strlen(str), 10, 10, &u));
- assert_int_equal(u, 10);
+ assert_int_equal(LY_SUCCESS, lyd_new_term(NULL, mod, "l", str, 0, &node));
+ assert_string_equal("10", lyd_get_value(node));
/* leading zeros are allowed, trailing whitespaces are allowed */
str = "000\n\t ";
- assert_int_equal(LY_SUCCESS, ly_parse_uint(str, strlen(str), 10, 10, &u));
- assert_int_equal(u, 0);
- /* non-NULL terminated string */
- str = "+5sometext";
- assert_int_equal(LY_SUCCESS, ly_parse_uint(str, 2, 10, 10, &u));
- assert_int_equal(u, 5);
+ assert_int_equal(LY_SUCCESS, lyd_change_term(node, str));
+ assert_string_equal("0", lyd_get_value(node));
/* out of bounds value */
- str = "11";
- assert_int_equal(LY_EDENIED, ly_parse_uint(str, strlen(str), 10, 10, &u));
+ str = "256";
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
+
str = "-1";
- assert_int_equal(LY_EDENIED, ly_parse_uint(str, strlen(str), (uint64_t)-1, 10, &u));
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
/* NaN */
str = "zero";
- assert_int_equal(LY_EVALID, ly_parse_uint(str, strlen(str), 10, 10, &u));
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
/* mixing number with text */
str = "10zero";
- assert_int_equal(LY_EVALID, ly_parse_uint(str, strlen(str), 10, 10, &u));
+ assert_int_equal(LY_EVALID, lyd_change_term(node, str));
+ UTEST_LOG_CTX_CLEAN;
- str = "10 zero";
- assert_int_equal(LY_EVALID, ly_parse_uint(str, strlen(str), 10, 10, &u));
+ lyd_free_all(node);
}
static void
-test_parse_nodeid(void **UNUSED(state))
+test_parse_nodeid(void **state)
{
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lys_module *mod_data = NULL;
+ struct lys_module *mod_meta = NULL;
+ struct lyd_node *node = NULL;
+ struct lyd_meta *meta = NULL;
const char *str;
- const char *prefix, *name;
- uint32_t prefix_len, name_len;
-
+ const char *yang_meta =
+ "module my-meta {"
+ " namespace \"urn:my-meta\";"
+ " prefix mm;"
+ " import ietf-yang-metadata { prefix md; }"
+ " md:annotation a12_-. {"
+ " type string;"
+ " }\n"
+ "}";
+ const char *yang_data =
+ "module my-data {"
+ " namespace \"urn:my-data\";"
+ " prefix md;"
+ " leaf interface { type string; }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang_meta, LYS_IN_YANG, &mod_meta));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang_data, LYS_IN_YANG, &mod_data));
+
+ /* invalid starting character */
+ lyd_new_path(NULL, ctx, "/my-data:interface", "eth0", 0, &node);
str = "123";
- assert_int_equal(LY_EINVAL, ly_parse_nodeid(&str, &prefix, &prefix_len, &name, &name_len));
+ assert_int_equal(LY_EINVAL, lyd_new_meta(ctx, node, mod_meta, str, "delete", 0, &meta));
+ UTEST_LOG_CTX_CLEAN;
+ /* invalid character in the name */
str = "a12_-.!";
- assert_int_equal(LY_SUCCESS, ly_parse_nodeid(&str, &prefix, &prefix_len, &name, &name_len));
- assert_null(prefix);
- assert_int_equal(0, prefix_len);
- assert_non_null(name);
- assert_int_equal(6, name_len);
- assert_int_equal(0, strncmp("a12_-.", name, name_len));
- assert_string_equal("!", str);
-
- str = "a12_-.:_b2 xxx";
- assert_int_equal(LY_SUCCESS, ly_parse_nodeid(&str, &prefix, &prefix_len, &name, &name_len));
- assert_non_null(prefix);
- assert_int_equal(6, prefix_len);
- assert_int_equal(0, strncmp("a12_-.", prefix, prefix_len));
- assert_non_null(name);
- assert_int_equal(3, name_len);
- assert_int_equal(0, strncmp("_b2", name, name_len));
- assert_string_equal(" xxx", str);
+ assert_int_equal(LY_EINVAL, lyd_new_meta(ctx, node, mod_meta, str, "delete", 0, &meta));
+ UTEST_LOG_CTX_CLEAN;
+
+ /* correct name */
+ str = "a12_-.";
+ assert_int_equal(LY_SUCCESS, lyd_new_meta(ctx, node, mod_meta, str, "delete", 0, &meta));
+ lyd_free_all(node);
}
static void
-test_parse_instance_predicate(void **UNUSED(state))
+test_parse_instance_predicate(void **state)
{
- const char *str, *errmsg;
- const char *prefix, *id, *value;
- uint32_t prefix_len, id_len, value_len;
-
- str = "[ex:name='fred']";
- assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(str, "");
- assert_string_equal(prefix, "ex:name='fred']");
- assert_int_equal(prefix_len, 2);
- assert_string_equal(id, "name='fred']");
- assert_int_equal(id_len, 4);
- assert_string_equal(value, "fred']");
- assert_int_equal(value_len, 4);
-
- str = "[ex:ip = \"[192.0.2.1]\"][ex:port='80']";
- assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(str, "[ex:port='80']");
- assert_string_equal(prefix, "ex:ip = \"[192.0.2.1]\"][ex:port='80']");
- assert_int_equal(prefix_len, 2);
- assert_string_equal(id, "ip = \"[192.0.2.1]\"][ex:port='80']");
- assert_int_equal(id_len, 2);
- assert_string_equal(value, "[192.0.2.1]\"][ex:port='80']");
- assert_int_equal(value_len, 11);
-
- str = "[. = 'blowfish-cbc']";
- assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(str, "");
- assert_null(prefix);
- assert_int_equal(prefix_len, 0);
- assert_string_equal(id, ". = 'blowfish-cbc']");
- assert_int_equal(id_len, 1);
- assert_string_equal(value, "blowfish-cbc']");
- assert_int_equal(value_len, 12);
-
- str = "[ 3 ]";
- assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(str, "");
- assert_null(prefix);
- assert_int_equal(prefix_len, 0);
- assert_null(id);
- assert_int_equal(id_len, 0);
- assert_string_equal(value, "3 ]");
- assert_int_equal(value_len, 1);
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lys_module *mod = NULL;
+ struct lyd_node *node = NULL;
+ struct lyd_node *tree = NULL;
+ struct ly_set *set = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " list user {"
+ " key \"name\";"
+ " leaf name { "
+ " type string;"
+ " }"
+ " } "
+ " list router {"
+ " key \"ip port\";"
+ " leaf ip { type string; }"
+ " leaf port { type uint16; }"
+ " } "
+ " leaf-list cipher {"
+ " type string;"
+ " }"
+ " leaf l {"
+ " type instance-identifier {"
+ " require-instance false;"
+ " }"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, &mod));
+
+ /* correct predicates */
+ assert_int_equal(LY_SUCCESS, lyd_new_term(NULL, mod, "l", "/test:user[name='fred']", 0, &node));
+ lyd_free_all(node);
+ assert_int_equal(LY_SUCCESS, lyd_new_term(NULL, mod, "l", "/test:router[ip='192.0.2.1'][port='80']", 0, &node));
+ lyd_free_all(node);
+ assert_int_equal(LY_SUCCESS, lyd_new_term(NULL, mod, "l", "/test:cipher[. = 'blowfish-cbc']", 0, &node));
+ lyd_free_all(node);
+
+ assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, ctx, "/test:user[name='alice']", NULL, 0, &tree));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(tree, ctx, "/test:user[name='bob']", NULL, 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(tree, ctx, "/test:user[name='cyril']", NULL, 0, NULL));
+
+ assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/test:user[ 3 ]", &set));
+ assert_non_null(set);
+ assert_int_equal(1, set->count);
+ ly_set_free(set, NULL);
/* invalid predicates */
- /* position must be positive integer */
- str = "[0]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "The position predicate cannot be zero.");
- str = "[-1]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Invalid instance predicate format (negative position or invalid node-identifier).");
+ assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/test:user[ 0 ]", &set));
+ assert_non_null(set);
+ assert_int_equal(0, set->count);
+ ly_set_free(set, NULL);
+
+ assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/test:user[ -1 ]", &set));
+ assert_non_null(set);
+ assert_int_equal(0, set->count);
+ ly_set_free(set, NULL);
/* invalid node-identifier */
- str = "[$node='value']";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Invalid node-identifier.");
- str = "[.node='value']";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Unexpected character instead of '=' in leaf-list-predicate.");
- str = "[13node='value']";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Predicate (pos) is not terminated by \']\' character.");
-
- str = "[ex:node]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Unexpected character instead of '=' in key-predicate.");
-
- str = "[ex:node= value]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "String value is not quoted.");
-
- str = "[ex:node='value\"]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Value is not terminated quoted-string.");
-
- str = "[ex:node='value ]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Value is not terminated quoted-string.");
-
- str = "[ex:node=\"value\"[3]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Predicate (key-predicate) is not terminated by \']\' character.");
- str = "[.=\"value\"[3]";
- assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Predicate (leaf-list-predicate) is not terminated by \']\' character.");
-
- /* the limit of the string is too short, it ends one character earlier */
- str = "[ex:node='value']";
- assert_int_equal(LY_EINVAL, ly_parse_instance_predicate(&str, strlen(str) - 1, LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
- assert_string_equal(errmsg, "Predicate is incomplete.");
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[$name='fred']", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[.name='fred']", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[13name='fred']", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[name]", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[name= fred]", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[name='fred\"]", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:user[name=\"fred\"[3]", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_new_term(NULL, mod, "l", "/test:cipher[.=\"value\"[3]", 0, &node));
+ UTEST_LOG_CTX_CLEAN;
+
+ lyd_free_all(tree);
}
+/**
+ * @brief Helper function to test token translation.
+ *
+ * @param token The input token to translate.
+ * @param tok_len The length of the input token.
+ * @param is_nametest Whether the token is a name test.
+ * @param mod The YANG module.
+ * @param expected_ret The expected return value.
+ * @param expected_out The expected output token.
+ */
static void
-test_value_prefix_next(void **UNUSED(state))
+assert_token_translation(const char *token, uint16_t tok_len, ly_bool is_nametest,
+ struct lys_module *mod, LY_ERR expected_ret)
{
- const char *next;
- ly_bool is_prefix;
- uint32_t bytes;
-
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(NULL, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(0, bytes);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next("", NULL, &bytes, &is_prefix, &next));
- assert_int_equal(0, bytes);
-
- /* prefix */
- next = "pref:";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(1, is_prefix);
-
- /* no-prefix */
- next = "node";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
-
- /* no-prefix */
- next = "::::";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
-
- /* no-prefix */
- next = "//a/:";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(5, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
-
- /* no-prefix */
- next = "//a//";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(5, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
-
- /* prefix, prefix */
- next = "pref1:pref2:";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(5, bytes);
- assert_string_equal(next, "pref2:");
- assert_int_equal(1, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(5, bytes);
- assert_null(next);
- assert_int_equal(1, is_prefix);
-
- /* prefix, no-prefix */
- next = "pref:node";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_string_equal(next, "node");
- assert_int_equal(1, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
-
- /* no-prefix, prefix */
- next = "/pref:";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(1, bytes);
- assert_string_equal(next, "pref:");
- assert_int_equal(0, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(1, is_prefix);
-
- /* no-prefix, prefix */
- next = "//pref:";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(2, bytes);
- assert_string_equal(next, "pref:");
- assert_int_equal(0, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(1, is_prefix);
-
- /* no-prefix, prefix, no-prefix */
- next = "/pref:node";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(1, bytes);
- assert_string_equal(next, "pref:node");
- assert_int_equal(0, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_string_equal(next, "node");
- assert_int_equal(1, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
-
- /* prefix, no-prefix, prefix */
- next = "pref:node pref:";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_string_equal(next, "node pref:");
- assert_int_equal(1, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(5, bytes);
- assert_string_equal(next, "pref:");
- assert_int_equal(0, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(1, is_prefix);
-
- /* prefix, no-prefix, prefix, no-prefix */
- next = "pref:node /pref:node";
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_string_equal(next, "node /pref:node");
- assert_int_equal(1, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(6, bytes);
- assert_string_equal(next, "pref:node");
- assert_int_equal(0, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_string_equal(next, "node");
- assert_int_equal(1, is_prefix);
- assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
- assert_int_equal(4, bytes);
- assert_null(next);
- assert_int_equal(0, is_prefix);
+ char *out_token = NULL;
+ const struct lys_module *context_mod = mod;
+
+ LY_ERR ret = lyplg_type_xpath10_print_token(
+ token,
+ tok_len,
+ is_nametest,
+ &context_mod,
+ mod->ctx,
+ LY_VALUE_SCHEMA,
+ mod->parsed,
+ LY_VALUE_JSON,
+ NULL,
+ &out_token,
+ NULL);
+
+ assert_int_equal(expected_ret, ret);
+ free(out_token);
+}
+
+static void
+test_value_prefix_next(void **state)
+{
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lys_module *mod = NULL;
+ const char *yang =
+ "module test {"
+ " namespace \"urn:test\";"
+ " prefix pref;"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, &mod));
+
+ /* Empty/NULL token */
+ assert_token_translation("", 0, 1, mod, LY_SUCCESS);
+
+ /* Valid prefix with node (Prefix translation) */
+ assert_token_translation("pref:node", 9, 1, mod, LY_SUCCESS);
+
+ /* Valid prefix only (Nametest ending in colon) */
+ assert_token_translation("pref:", 5, 1, mod, LY_SUCCESS);
+
+ /* No prefix (Standard node) */
+ assert_token_translation("node", 4, 1, mod, LY_SUCCESS);
+
+ /* Unresolved prefix */
+ assert_token_translation("pref1:node", 10, 1, mod, LY_EVALID);
+ UTEST_LOG_CTX_CLEAN;
+
+ /* Invalid token syntax (e.g., "::::") */
+ assert_token_translation("::::", 4, 1, mod, LY_SUCCESS);
}
int
diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c
index 1b549ab0b1..32a693c5c3 100644
--- a/tests/utests/basic/test_context.c
+++ b/tests/utests/basic/test_context.c
@@ -16,12 +16,20 @@
#include "context.h"
#include "in.h"
-#include "ly_common.h"
-#include "schema_compile.h"
-#include "tests_config.h"
-#include "tree_schema_internal.h"
+
+static int
+get_dirs_count(const char * const *list)
+{
+ int count = 0;
+
+ while (list[count]) {
+ count++;
+ }
+ return count;
+}
#ifdef _WIN32
+# define PATH_SEPARATOR ";"
static void
slashes_to_backslashes(char *path)
@@ -50,18 +58,24 @@ test_searchdirs(void **state)
/* correct path */
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, path1));
- assert_int_equal(2, UTEST_LYCTX->search_paths.count);
- assert_string_equal(path1, UTEST_LYCTX->search_paths.objs[1]);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_non_null(list);
+ assert_int_equal(2, get_dirs_count(list));
+ assert_string_equal(path1, list[1]);
/* duplicated paths */
assert_int_equal(LY_EEXIST, ly_ctx_set_searchdir(UTEST_LYCTX, path1));
- assert_int_equal(2, UTEST_LYCTX->search_paths.count);
- assert_string_equal(path1, UTEST_LYCTX->search_paths.objs[1]);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_non_null(list);
+ assert_int_equal(2, get_dirs_count(list));
+ assert_string_equal(path1, list[1]);
/* another path */
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, path2));
- assert_int_equal(3, UTEST_LYCTX->search_paths.count);
- assert_string_equal(path2, UTEST_LYCTX->search_paths.objs[2]);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_non_null(list);
+ assert_int_equal(3, get_dirs_count(list));
+ assert_string_equal(path2, list[2]);
/* get searchpaths */
list = ly_ctx_get_searchdirs(UTEST_LYCTX);
@@ -77,18 +91,21 @@ test_searchdirs(void **state)
/* first */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, path1));
- assert_int_equal(2, UTEST_LYCTX->search_paths.count);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_non_null(list);
+ assert_int_equal(2, get_dirs_count(list));
assert_string_not_equal(path1, list[1]);
/* second */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, path2));
- assert_int_equal(1, UTEST_LYCTX->search_paths.count);
+ assert_int_equal(1, get_dirs_count(list));
free(path1);
free(path2);
}
#else
+# define PATH_SEPARATOR ":"
static void
test_searchdirs(void **state)
@@ -116,13 +133,17 @@ test_searchdirs(void **state)
/* correct path */
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/utests"));
- assert_int_equal(2, UTEST_LYCTX->search_paths.count);
- assert_string_equal(TESTS_BIN "/utests", UTEST_LYCTX->search_paths.objs[1]);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_non_null(list);
+ assert_int_equal(2, get_dirs_count(list));
+ assert_string_equal(TESTS_BIN "/utests", list[1]);
/* duplicated paths */
assert_int_equal(LY_EEXIST, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/utests"));
- assert_int_equal(2, UTEST_LYCTX->search_paths.count);
- assert_string_equal(TESTS_BIN "/utests", UTEST_LYCTX->search_paths.objs[1]);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_non_null(list);
+ assert_int_equal(2, get_dirs_count(list));
+ assert_string_equal(TESTS_BIN "/utests", list[1]);
/* another paths - add 8 to fill the initial buffer of the searchpaths list */
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/CMakeFiles"));
@@ -131,11 +152,11 @@ test_searchdirs(void **state)
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_SRC "/../doc"));
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_SRC));
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN));
- assert_int_equal(8, UTEST_LYCTX->search_paths.count);
/* get searchpaths */
list = ly_ctx_get_searchdirs(UTEST_LYCTX);
assert_non_null(list);
+ assert_int_equal(8, get_dirs_count(list));
assert_string_equal(TESTS_BIN "/utests", list[1]);
assert_string_equal(TESTS_BIN "/CMakeFiles", list[2]);
assert_string_equal(TESTS_SRC, list[6]);
@@ -149,16 +170,19 @@ test_searchdirs(void **state)
/* first */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, TESTS_BIN "/utests"));
assert_string_not_equal(TESTS_BIN "/utests", list[0]);
- assert_int_equal(7, UTEST_LYCTX->search_paths.count);
+ assert_int_equal(7, get_dirs_count(list));
/* middle */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, TESTS_SRC));
- assert_int_equal(6, UTEST_LYCTX->search_paths.count);
+ assert_int_equal(6, get_dirs_count(list));
+
/* last */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, TESTS_BIN));
- assert_int_equal(5, UTEST_LYCTX->search_paths.count);
+ assert_int_equal(5, get_dirs_count(list));
+
/* all */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, NULL));
- assert_int_equal(0, UTEST_LYCTX->search_paths.count);
+ list = ly_ctx_get_searchdirs(UTEST_LYCTX);
+ assert_int_equal(0, get_dirs_count(list));
/* again - no change */
assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, NULL));
@@ -205,7 +229,9 @@ test_models(void **state)
struct ly_in *in;
const char *str;
struct lys_module *mod1, *mod2;
- struct lys_glob_unres unres = {0};
+ uint16_t initial_change_count, change_count;
+ ly_module_imp_clb clb;
+ void *clb_data;
/* use own context with extra flags */
ly_ctx_destroy(UTEST_LYCTX);
@@ -215,59 +241,59 @@ test_models(void **state)
CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_change_count()).");
assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_SRC "/../modules", LY_CTX_DISABLE_SEARCHDIR_CWD, &UTEST_LYCTX));
- assert_int_equal(UTEST_LYCTX->change_count, ly_ctx_get_change_count(UTEST_LYCTX));
+ initial_change_count = ly_ctx_get_change_count(UTEST_LYCTX);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module x {namespace urn:x;prefix x;}", &in));
- assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, 4, NULL, &unres.creating, &mod1));
- lys_unres_glob_erase(&unres);
+ lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL);
+ change_count = ly_ctx_get_change_count(UTEST_LYCTX);
+ assert_true(change_count > initial_change_count);
+
+ assert_int_equal(LY_EINVAL, lys_parse(UTEST_LYCTX, in, 4, NULL, &mod1));
ly_in_free(in, 0);
CHECK_LOG_CTX("Invalid schema input format.", NULL, 0);
/* import callback */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)(str = "test"));
- assert_ptr_equal(test_imp_clb, UTEST_LYCTX->imp_clb);
- assert_ptr_equal(str, UTEST_LYCTX->imp_clb_data);
+ clb = ly_ctx_get_module_imp_clb(UTEST_LYCTX, &clb_data);
+ assert_ptr_equal(test_imp_clb, clb);
+ assert_ptr_equal(str, clb_data);
assert_ptr_equal(test_imp_clb, ly_ctx_get_module_imp_clb(UTEST_LYCTX, (void **)&str));
assert_string_equal("test", str);
ly_ctx_set_module_imp_clb(UTEST_LYCTX, NULL, NULL);
- assert_null(UTEST_LYCTX->imp_clb);
- assert_null(UTEST_LYCTX->imp_clb_data);
+ clb = ly_ctx_get_module_imp_clb(UTEST_LYCTX, &clb_data);
+ assert_null(clb);
+ assert_null(clb_data);
/* name collision of module and submodule */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-30;}");
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;include y;}", &in));
- assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
- lys_unres_glob_erase(&unres);
+ assert_int_equal(LY_EVALID, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod1));
ly_in_free(in, 0);
CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, 0);
CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", NULL, 1);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", &in));
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
+ assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod1));
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;}", &in));
- assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
- lys_unres_glob_erase(&unres);
+ assert_int_equal(LY_EVALID, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod1));
ly_in_free(in, 0);
CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, 0);
CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", NULL, 1);
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to b {prefix b;}}");
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module b {namespace urn:b;prefix b;include y;}", &in));
- assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
- lys_unres_glob_revert(UTEST_LYCTX, &unres);
- lys_unres_glob_erase(&unres);
+ assert_int_equal(LY_EVALID, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod1));
ly_in_free(in, 0);
CHECK_LOG_CTX("Parsing module \"b\" failed.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule \"y\" failed.", NULL, 0);
CHECK_LOG_CTX("Name collision between submodules of name \"y\".", NULL, 1);
/* selecting correct revision of the submodules */
- ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-31;}");
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", &in));
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod2));
- lys_unres_glob_erase(&unres);
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule p {belongs-to g {prefix g;} revision 2018-10-31;}");
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory("module g {namespace urn:g;prefix g;include p; revision 2018-10-31;}", &in));
+ assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod2));
ly_in_free(in, 0);
assert_string_equal("2018-10-31", mod2->parsed->includes[0].submodule->revs[0].date);
@@ -372,17 +398,16 @@ test_includes(void **state)
static void
test_get_models(void **state)
{
- struct lys_module *mod, *mod2;
+ struct lys_module *mod, *mod2, *latest;
const char *str0 = "module a {namespace urn:a;prefix a;}";
const char *str1 = "module a {namespace urn:a;prefix a;revision 2018-10-23;}";
const char *str2 = "module a {namespace urn:a;prefix a;revision 2018-10-24;revision 2018-10-23;}";
- struct ly_in *in0, *in1, *in2;
- struct lys_glob_unres unres = {0};
+ struct ly_in *in0, *in1, *in2, *in3;
unsigned int index = 0;
const char *names[] = {
"ietf-inet-types", "ietf-yang-types", "ietf-yang-metadata", "yang", "default", "ietf-yang-schema-mount",
- "ietf-yang-structure-ext", "ietf-datastores", "ietf-yang-library", "a", "a", "a"
+ "ietf-yang-structure-ext", "ietf-datastores", "ietf-yang-library", "a", "m", "a", "n"
};
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str0, &in0));
@@ -416,46 +441,44 @@ test_get_models(void **state)
/* select module by revision */
assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &mod));
/* invalid attempts - implementing module of the same name and inserting the same module */
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, &unres.creating, &mod2));
- assert_int_equal(LY_EDENIED, lys_implement(mod2, NULL, &unres));
+ assert_int_equal(LY_EDENIED, lys_parse(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, &mod2));
CHECK_LOG_CTX("Module \"a@2018-10-24\" is already implemented in revision \"2018-10-23\".", NULL, 0);
- lys_unres_glob_erase(&unres);
ly_in_reset(in1);
/* it is already there, fine */
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &unres.creating, NULL));
+ assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, NULL));
/* insert the second module only as imported, not implemented */
- lys_unres_glob_erase(&unres);
- ly_in_reset(in2);
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, &unres.creating, &mod2));
- lys_unres_glob_erase(&unres);
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)str2);
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory("module m {namespace urn:m; prefix m; import a { prefix a; revision-date 2018-10-24; }}", &in3));
+ assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in3, LYS_IN_YANG, NULL, NULL));
+ ly_in_free(in3, 0);
+ mod2 = ly_ctx_get_module(UTEST_LYCTX, "a", "2018-10-24");
assert_non_null(mod2);
assert_ptr_not_equal(mod, mod2);
- mod = ly_ctx_get_module_latest(UTEST_LYCTX, "a");
- assert_ptr_equal(mod, mod2);
- mod2 = ly_ctx_get_module_latest_ns(UTEST_LYCTX, mod->ns);
- assert_ptr_equal(mod, mod2);
- /* work with module with no revision */
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in0, LYS_IN_YANG, NULL, &unres.creating, &mod));
- lys_unres_glob_erase(&unres);
- assert_ptr_equal(mod, ly_ctx_get_module(UTEST_LYCTX, "a", NULL));
- assert_ptr_not_equal(mod, ly_ctx_get_module_latest(UTEST_LYCTX, "a"));
+ latest = ly_ctx_get_module_latest(UTEST_LYCTX, "a");
+ assert_ptr_equal(latest, mod2);
+ assert_ptr_equal(latest, ly_ctx_get_module_latest_ns(UTEST_LYCTX, mod->ns));
+
+ /* work with module with no revision by using another module */
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)str0);
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory("module n {namespace urn:n; prefix n; import a { prefix a; }}", &in3));
+ assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in3, LYS_IN_YANG, NULL, NULL));
str1 = "submodule b {belongs-to a {prefix a;}}";
ly_in_free(in1, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str1, &in1));
- assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &unres.creating, &mod));
+ assert_int_equal(LY_EINVAL, lys_parse(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &mod));
CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0);
- lys_unres_glob_erase(&unres);
while ((mod = (struct lys_module *)ly_ctx_get_module_iter(UTEST_LYCTX, &index))) {
assert_string_equal(names[index - 1], mod->name);
}
- assert_int_equal(12, index);
+ assert_int_equal(13, index);
/* cleanup */
ly_in_free(in0, 0);
ly_in_free(in1, 0);
ly_in_free(in2, 0);
+ ly_in_free(in3, 0);
}
static void
diff --git a/tests/utests/basic/test_hash_table.c b/tests/utests/basic/test_hash_table.c
index 2ea34faab6..b02bd03bb1 100644
--- a/tests/utests/basic/test_hash_table.c
+++ b/tests/utests/basic/test_hash_table.c
@@ -17,7 +17,6 @@
#include
#include "hash_table.h"
-#include "ly_common.h"
static void
test_invalid_arguments(void **state)
@@ -104,24 +103,17 @@ test_ht_resize(void **UNUSED(state))
struct ly_ht *ht;
assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
- assert_int_equal(8, ht->size);
/* insert records into indexes 2-7 */
for (i = 2; i < 8; ++i) {
assert_int_equal(LY_SUCCESS, lyht_insert(ht, &i, i, NULL));
}
- /* check that table resized */
- assert_int_equal(16, ht->size);
/* check expected content of the table */
for (i = 0; i < 16; ++i) {
if ((i >= 2) && (i < 8)) {
- /* inserted data on indexes 2-7 */
- assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, i, NULL));
} else {
- /* nothing otherwise */
- assert_int_equal(UINT32_MAX, ht->hlists[i].first);
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
}
}
@@ -136,7 +128,6 @@ test_ht_resize(void **UNUSED(state))
for ( ; i < 5; ++i) {
assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
}
- assert_int_equal(8, ht->size);
/* remove the rest */
for ( ; i < 8; ++i) {
@@ -154,28 +145,16 @@ test_ht_resize(void **UNUSED(state))
static void
test_ht_collisions(void **UNUSED(state))
{
-#define GET_REC_INT(rec) (*((uint32_t *)&(rec)->val))
-
uint32_t i;
- struct ly_ht_rec *rec;
struct ly_ht *ht;
- uint32_t rec_idx;
- int count;
assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
for (i = 2; i < 6; ++i) {
- assert_int_equal(lyht_insert(ht, &i, 2, NULL), 0);
+ assert_int_equal(LY_SUCCESS, lyht_insert(ht, &i, 2, NULL));
}
/* check all records */
- for (i = 0; i < 8; ++i) {
- if (i == 2) {
- assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
- } else {
- assert_int_equal(UINT32_MAX, ht->hlists[i].first);
- }
- }
for (i = 0; i < 8; ++i) {
if ((i >= 2) && (i < 6)) {
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
@@ -183,32 +162,14 @@ test_ht_collisions(void **UNUSED(state))
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
}
}
- rec_idx = ht->hlists[2].first;
- count = 0;
- while (rec_idx != UINT32_MAX) {
- rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
- rec_idx = rec->next;
- assert_int_equal(rec->hash, 2);
- count++;
- }
- assert_int_equal(count, 4);
i = 4;
- assert_int_equal(lyht_remove(ht, &i, 2), 0);
-
- rec = lyht_get_rec(ht->recs, ht->rec_size, i);
+ assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, 2));
i = 2;
- assert_int_equal(lyht_remove(ht, &i, 2), 0);
+ assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, 2));
/* check all records */
- for (i = 0; i < 8; ++i) {
- if (i == 2) {
- assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
- } else {
- assert_int_equal(UINT32_MAX, ht->hlists[i].first);
- }
- }
for (i = 0; i < 8; ++i) {
if ((i == 3) || (i == 5)) {
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
@@ -216,32 +177,23 @@ test_ht_collisions(void **UNUSED(state))
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
}
}
- rec_idx = ht->hlists[2].first;
- count = 0;
- while (rec_idx != UINT32_MAX) {
- rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
- rec_idx = rec->next;
- assert_int_equal(rec->hash, 2);
- count++;
- }
- assert_int_equal(count, 2);
for (i = 0; i < 8; ++i) {
if ((i == 3) || (i == 5)) {
- assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS);
+ assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
} else {
- assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND);
+ assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
}
}
i = 3;
- assert_int_equal(lyht_remove(ht, &i, 2), 0);
+ assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, 2));
i = 5;
- assert_int_equal(lyht_remove(ht, &i, 2), 0);
+ assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, 2));
/* check all records */
for (i = 0; i < 8; ++i) {
- assert_int_equal(UINT32_MAX, ht->hlists[i].first);
+ assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
}
lyht_free(ht, NULL);
diff --git a/tests/utests/basic/test_inout.c b/tests/utests/basic/test_inout.c
index af8cc8112f..c7bf32bd3c 100644
--- a/tests/utests/basic/test_inout.c
+++ b/tests/utests/basic/test_inout.c
@@ -23,7 +23,6 @@
#include "in.h"
#include "log.h"
-#include "ly_common.h"
#include "out.h"
#define TEST_INPUT_FILE TESTS_BIN "/libyang_test_input"
diff --git a/tests/utests/basic/test_json.c b/tests/utests/basic/test_json.c
index a760b382ec..f50ac0498e 100644
--- a/tests/utests/basic/test_json.c
+++ b/tests/utests/basic/test_json.c
@@ -15,503 +15,442 @@
#include "utests.h"
#include "context.h"
-#include "in_internal.h"
-#include "json.h"
+
static void
test_general(void **state)
{
- struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf l {"
+ " type boolean;"
+ " }"
+ " leaf emp {"
+ " type empty;"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
/* empty */
str = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:l", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Empty JSON file.", NULL, 1);
str = " \n\t \n";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:l", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Empty JSON file.", NULL, 3);
/* constant values */
str = "true";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:l", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("true", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "false";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:l", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("false", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "null";
+ str = "[null]";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:emp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("", lyd_get_value(tree));
+ lyd_free_all(tree);
ly_in_free(in, 0);
}
static void
test_number(void **state)
{
- struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf num {"
+ " type union {"
+ " type int32;"
+ " type decimal64 {"
+ " fraction-digits 4;"
+ " }"
+ " }"
+ " }"
+ " leaf exp {"
+ " type string;"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
/* simple value */
str = "11";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("11", jsonctx->value);
- assert_int_equal(2, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("11", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* fraction number */
- str = "37.7668";
+ str = "\"37.7668\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("37.7668", jsonctx->value);
- assert_int_equal(7, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("37.7668", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* negative number */
- str = "-122.3959";
+ str = "\"-122.3959\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-122.3959", jsonctx->value);
- assert_int_equal(9, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-122.3959", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* integer, positive exponent */
str = "550E3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("550000", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("550000", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+ /* integer, negative exponent */
str = "-550E3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-550000", jsonctx->value);
- assert_int_equal(7, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-550000", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* integer, negative exponent */
- str = "1E-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.1", jsonctx->value);
- assert_int_equal(3, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "15E-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("1.5", jsonctx->value);
- assert_int_equal(3, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "-15E-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-1.5", jsonctx->value);
- assert_int_equal(4, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "16E-2";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.16", jsonctx->value);
- assert_int_equal(4, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "-16E-2";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-0.16", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "17E-3";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.017", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "-17E-3";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-0.017", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ str = "\"1E-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("1E-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"15E-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("15E-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"-15E-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-15E-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"16E-2\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("16E-2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"-16E-2\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-16E-2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"17E-3\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("17E-3", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"-17E-3\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-17E-3", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "21000E-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("210", jsonctx->value);
- assert_int_equal(3, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("210", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "21000E-4";
+ str = "\"21000E-4\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("2.1", jsonctx->value);
- assert_int_equal(3, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("21000E-4", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "21000E-7";
+ str = "\"21000E-7\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.0021", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("21000E-7", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* decimal number, positive exponent */
- str = "5.087E1";
+ str = "\"5.087E1\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("50.87", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("5.087E1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "-5.087E1";
+ str = "\"-5.087E1\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-50.87", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-5.087E1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "5.087E5";
+ str = "\"5.087E5\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("508700", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("5.087E5", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "59.1e+1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("591", jsonctx->value);
- assert_int_equal(3, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("591", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "0.005087E1";
+ str = "\"0.005087E1\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.05087", jsonctx->value);
- assert_int_equal(7, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.005087E1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "0.005087E2";
+ str = "\"0.005087E2\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.5087", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.005087E2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "0.005087E6";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("5087", jsonctx->value);
- assert_int_equal(4, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("5087", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "0.05087E6";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("50870", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("50870", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "0.005087E8";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("508700", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("508700", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* decimal number, negative exponent */
- str = "35.94e-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("3.594", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "-35.94e-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("-3.594", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "35.94e-2";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.3594", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "35.94e-3";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.03594", jsonctx->value);
- assert_int_equal(7, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "0.3594e-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.03594", jsonctx->value);
- assert_int_equal(7, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "0.03594e-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.003594", jsonctx->value);
- assert_int_equal(8, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "0.003594e-1";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.0003594", jsonctx->value);
- assert_int_equal(9, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "0.3594e-2";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.003594", jsonctx->value);
- assert_int_equal(8, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "0.03594e-2";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.0003594", jsonctx->value);
- assert_int_equal(9, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
-
- str = "0.003594e-2";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.00003594", jsonctx->value);
- assert_int_equal(10, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ str = "\"35.94e-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("35.94e-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"-35.94e-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("-35.94e-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"35.94e-2\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("35.94e-2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"35.94e-3\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("35.94e-3", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"0.3594e-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.3594e-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"0.03594e-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.03594e-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"0.003594e-1\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.003594e-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"0.3594e-2\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.3594e-2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"0.03594e-2\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.03594e-2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
+
+ str = "\"0.003594e-2\"";
+ assert_non_null(ly_in_memory(in, str));
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0.003594e-2", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* zero */
str = "0";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_true(jsonctx->value[0] == '0');
- assert_int_equal(1, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "-0";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_true(jsonctx->value[0] == '-');
- assert_true(jsonctx->value[1] == '0');
- assert_int_equal(2, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "94E0";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_true(jsonctx->value[0] == '9');
- assert_true(jsonctx->value[1] == '4');
- assert_int_equal(2, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("94", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "0E2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_true(jsonctx->value[0] == '0');
- assert_int_equal(1, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "-0E2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_true(jsonctx->value[0] == '-');
- assert_true(jsonctx->value[1] == '0');
- assert_int_equal(2, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("0", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
str = "5.320e+2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("532", jsonctx->value);
- assert_int_equal(3, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("532", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
- str = "5.320e-1";
+ str = "\"5.320e-1\"";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
- assert_string_equal("0.532", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(1, jsonctx->dynamic);
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:exp", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_string_equal("5.320e-1", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* various invalid inputs */
str = "-x";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", NULL, 1);
str = " -";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
str = "--1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"-\").", NULL, 1);
str = "+1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Invalid character sequence \"+1\", expected a JSON value.", NULL, 1);
str = " 1.x ";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", NULL, 1);
str = "1.";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
str = " 1eo ";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"o\").", NULL, 1);
str = "1e";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
str = "1E1000";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.", NULL, 1);
str = "1e9999999999999999999";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1e9999999999999999999).", NULL, 1);
str = "1.1e66000";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e66000).", NULL, 1);
str = "1.1e-66000";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:num", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e-66000).", NULL, 1);
ly_in_free(in, 0);
@@ -521,9 +460,19 @@ test_number(void **state)
static void
test_string(void **state)
{
- struct lyjson_ctx *jsonctx;
struct ly_in *in = NULL;
const char *str;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf l {"
+ " type string;"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
str = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
@@ -531,7 +480,7 @@ test_string(void **state)
/* unterminated string */
str = "\"unterminated string";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LY_EVALID, lyd_parse_value_fragment(ctx, "/test:l", in, LYD_JSON, 0, 0, 0, &tree));
CHECK_LOG_CTX("Missing quotation-mark at the end of a JSON string.", NULL, 1);
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
@@ -541,129 +490,67 @@ test_string(void **state)
static void
test_object(void **state)
{
- struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree, *search_node;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf name {"
+ " type string;"
+ " }"
+ " leaf smart {"
+ " type boolean;"
+ " }"
+ " leaf handsom {"
+ " type boolean;"
+ " }"
+ " container person {"
+ " leaf name {"
+ " type string;"
+ " }"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
/* empty */
str = " { } ";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_parse_value_fragment(ctx, "/test:name", in, LYD_JSON, 0, 0, 0, &tree));
+ assert_null(tree);
/* simple value */
- str = "{\"name\" : \"Radek\"}";
- assert_non_null(ly_in_memory(in, str));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
- assert_ptr_equal(&str[2], jsonctx->value);
- assert_int_equal(4, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
- assert_string_equal("Radek\"}", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ str = "{\"test:name\" : \"Radek\"}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_string_equal("Radek", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* two values */
- str = "{\"smart\" : true,\"handsom\":false}";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
- assert_string_equal("smart\" : true,\"handsom\":false}", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NEXT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
- assert_string_equal("handsom\":false}", jsonctx->value);
- assert_int_equal(7, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+ str = "{\"test:smart\" : true,\"test:handsom\":false}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_SUCCESS, lyd_find_path(tree, "/test:smart", 0, &search_node));
+ assert_string_equal("true", lyd_get_value(search_node));
+ assert_int_equal(LY_SUCCESS, lyd_find_path(tree, "/test:handsom", 0, &search_node));
+ assert_string_equal("false", lyd_get_value(search_node));
+ lyd_free_all(tree);
+ tree = NULL;
/* inherited objects */
- str = "{\"person\" : {\"name\":\"Radek\"}}";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
- assert_string_equal("person\" : {\"name\":\"Radek\"}}", jsonctx->value);
- assert_int_equal(6, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
- assert_string_equal("name\":\"Radek\"}}", jsonctx->value);
- assert_int_equal(4, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
- assert_string_equal("Radek\"}}", jsonctx->value);
- assert_int_equal(5, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ str = "{\"test:person\" : {\"name\":\"Radek\"}}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_int_equal(LY_SUCCESS, lyd_find_path(tree, "/test:person/name", 0, &search_node));
+ assert_string_equal("Radek", lyd_get_value(search_node));
+ lyd_free_all(tree);
+ tree = NULL;
/* unquoted string */
str = "{ unquoted : \"data\"}";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object name.", NULL, 1);
- lyjson_ctx_free(jsonctx);
ly_in_free(in, 0);
}
@@ -671,91 +558,35 @@ test_object(void **state)
static void
test_array(void **state)
{
- struct lyjson_ctx *jsonctx;
- struct ly_in *in;
const char *str;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
/* empty */
- str = " [ ] ";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ str = "{\"mod:mixed-stuff\": [] }";
+ assert_int_equal(LY_EINVAL, lyd_parse_data_mem(ctx, str, LYD_JSON,
+ LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, &tree));
+ CHECK_LOG_CTX("Unexpected input data array closed.", NULL, 1);
/* simple value */
- str = "[ null]";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
- assert_null(jsonctx->value);
- assert_int_equal(0, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ str = "{\"mod:mixed-stuff\": [ null ]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_JSON,
+ LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, &tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* two values */
- str = "[{\"a\":null},\"x\"]";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
- assert_null(jsonctx->value);
- assert_int_equal(0, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
- assert_string_equal("a\":null},\"x\"]", jsonctx->value);
- assert_int_equal(1, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_ARRAY_NEXT, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
- assert_string_equal("x\"]", jsonctx->value);
- assert_int_equal(1, jsonctx->value_len);
- assert_int_equal(0, jsonctx->dynamic);
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
-
- assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
- lyjson_ctx_free(jsonctx);
+ str = "{\"mod:mixed-stuff\": [{\"a\":null},\"x\"]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_JSON,
+ LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, &tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* new line is allowed only as escaped character in JSON */
- str = "[ , null]";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
- assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
- CHECK_LOG_CTX("Invalid character sequence \", null]\", expected a JSON value.", NULL, 1);
- lyjson_ctx_free(jsonctx);
-
- ly_in_free(in, 0);
+ str = "{\"mod:mixed-stuff\": [ , null]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_JSON,
+ LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, &tree));
+ CHECK_LOG_CTX("Invalid character sequence \", null]}\", expected a JSON value.", NULL, 1);
}
int
diff --git a/tests/utests/basic/test_plugins.c b/tests/utests/basic/test_plugins.c
index 3926b2ceb7..8a39d5fd3d 100644
--- a/tests/utests/basic/test_plugins.c
+++ b/tests/utests/basic/test_plugins.c
@@ -17,9 +17,7 @@
#include
#include
-#include "ly_config.h"
#include "plugins.h"
-#include "plugins_internal.h"
const char *simple = "module libyang-plugins-simple {"
" namespace urn:libyang:tests:plugins:simple;"
@@ -79,6 +77,7 @@ test_add_simple(void **state)
struct lysc_node_leaf *leaf;
struct lyplg_ext *plugin_e;
struct lyplg_type *plugin_t;
+ uintptr_t plugin_ptr;
assert_int_equal(LY_SUCCESS, lyplg_add(TESTS_BIN "/plugins/plugin_simple" LYPLG_SUFFIX));
@@ -87,12 +86,14 @@ test_add_simple(void **state)
leaf = (struct lysc_node_leaf *)mod->compiled->data;
assert_int_equal(LYS_LEAF, leaf->nodetype);
- assert_non_null(plugin_t = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "libyang-plugins-simple", NULL, "note")));
+ plugin_ptr = leaf->type->plugin_ref;
+ assert_non_null(plugin_t = lysc_get_type_plugin(plugin_ptr));
assert_string_equal("ly2 simple test v1", plugin_t->id);
assert_ptr_equal(leaf->type->plugin_ref, plugin_t);
assert_int_equal(1, LY_ARRAY_COUNT(leaf->exts));
- assert_non_null(plugin_e = lysc_get_ext_plugin(lyplg_ext_plugin_find(NULL, "libyang-plugins-simple", NULL, "hint")));
+ plugin_ptr = leaf->exts[0].def->plugin_ref;
+ assert_non_null(plugin_e = lysc_get_ext_plugin(plugin_ptr));
assert_string_equal("ly2 simple test v1", plugin_e->id);
assert_ptr_equal(leaf->exts[0].def->plugin_ref, plugin_e);
diff --git a/tests/utests/basic/test_xml.c b/tests/utests/basic/test_xml.c
index 49da606a92..5712f34685 100644
--- a/tests/utests/basic/test_xml.c
+++ b/tests/utests/basic/test_xml.c
@@ -21,658 +21,348 @@
#include
#include "context.h"
-#include "in_internal.h"
-#include "xml.h"
-
-LY_ERR lyxml_ns_add(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, char *uri);
static void
test_element(void **state)
{
- struct lyxml_ctx *xmlctx;
- struct ly_in *in;
const char *str;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf element {"
+ " type string;"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
/* empty */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
/* end element */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Stray closing element tag (\"element\").", NULL, 1);
- ly_in_free(in, 0);
/* no element */
str = "no data present";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"no data present\", expected element tag start ('<').", NULL, 1);
- ly_in_free(in, 0);
/* not supported DOCTYPE */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Document Type Declaration not supported.", NULL, 1);
- ly_in_free(in, 0);
/* invalid XML */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Unknown XML section \"\".", NULL, 1);
- ly_in_free(in, 0);
/* namespace ambiguity */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Duplicate default XML namespaces \"urn1\" and \"urn2\".", NULL, 1);
- ly_in_free(in, 0);
/* prefix duplicate */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Duplicate XML NS prefix \"a\" used for namespaces \"urn1\" and \"urn2\".", NULL, 1);
- ly_in_free(in, 0);
/* unqualified element */
str = " < element/>";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_null(xmlctx->prefix);
- assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
- assert_int_equal(1, xmlctx->elements.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp("", xmlctx->value, xmlctx->value_len));
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ UTEST_LOG_CTX_CLEAN;
/* element with attribute */
str = " < element attr=\'x\'/>";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
- assert_int_equal(1, xmlctx->elements.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
- assert_true(!strncmp("attr", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_int_equal(1, xmlctx->elements.count);
- assert_true(!strncmp("x", xmlctx->value, xmlctx->value_len));
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
- assert_int_equal(0, xmlctx->elements.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ UTEST_LOG_CTX_CLEAN;
/* headers and comments */
str = " ";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
- assert_int_equal(1, xmlctx->elements.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ UTEST_LOG_CTX_CLEAN;
/* separate opening and closing tags, neamespaced parsed internally */
- str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
- assert_int_equal(1, xmlctx->elements.count);
- assert_int_equal(1, xmlctx->ns.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
- assert_int_equal(0, xmlctx->elements.count);
- assert_int_equal(0, xmlctx->ns.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_string_equal("element", tree->schema->name);
+ assert_string_equal("", lyd_get_value(tree));
+ lyd_free_all(tree);
+ tree = NULL;
/* qualified element */
str = " < yin:element/>";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
- assert_true(!strncmp("yin", xmlctx->prefix, xmlctx->prefix_len));
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
/* non-matching closing tag */
- str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
- assert_true(!strncmp("yin", xmlctx->prefix, xmlctx->prefix_len));
- assert_int_equal(1, xmlctx->elements.count);
- assert_int_equal(1, xmlctx->ns.count);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
-
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
- CHECK_LOG_CTX("Opening (\"yin:element\") and closing (\"element\") elements tag mismatch.", NULL, 1);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LOG_CTX("Opening (\"t:element\") and closing (\"element\") elements tag mismatch.", NULL, 1);
/* invalid closing tag */
- str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"/>\", expected element tag termination ('>').", NULL, 1);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ UTEST_LOG_CTX_CLEAN;
/* UTF8 characters */
- str = "<𠜎€𠜎Øn:𠜎€𠜎Øn/>";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_true(!strncmp("𠜎€𠜎Øn", xmlctx->name, xmlctx->name_len));
- assert_true(!strncmp("𠜎€𠜎Øn", xmlctx->prefix, xmlctx->prefix_len));
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ str = "<𠜎€𠜎Øn:𠜎€𠜎Øn xmlns:𠜎€𠜎Øn=\"urn:test\"/>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_null(tree);
/* invalid UTF-8 characters */
str = "<¢:element>";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Identifier \"¢:element>\" starts with an invalid character.", NULL, 1);
- ly_in_free(in, 0);
- str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"⁐element>\", expected element tag end ('>' or '/>') or an attribute.", NULL, 1);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
/* mixed content */
str = "text x";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("a", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp("text ", xmlctx->value, xmlctx->value_len));
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("b", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp("x", xmlctx->value, xmlctx->value_len));
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ UTEST_LOG_CTX_CLEAN;
/* tag mismatch */
- str = "text";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_true(!strncmp("a", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp("text", xmlctx->value, xmlctx->value_len));
-
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "text";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Opening (\"a\") and closing (\"b\") elements tag mismatch.", NULL, 1);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+
}
static void
test_attribute(void **state)
{
const char *str;
- struct lyxml_ctx *xmlctx;
- struct ly_in *in;
- struct lyxml_ns *ns;
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " anyxml e;"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
/* not an attribute */
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"/>\", expected '='.", NULL, 1);
- ly_in_free(in, 0);
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"/>\", expected either single or double quotation mark.", NULL, 1);
- ly_in_free(in, 0);
str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"yyy/>\", expected either single or double quotation mark.", NULL, 2);
- ly_in_free(in, 0);
/* valid attribute */
- str = "status);
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
- assert_true(!strncmp("attr", xmlctx->name, xmlctx->name_len));
- assert_null(xmlctx->prefix);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_true(!strncmp("val", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 0);
- assert_int_equal(xmlctx->dynamic, 0);
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_string_equal("e", tree->schema->name);
+ lyd_free_all(tree);
+ tree = NULL;
/* valid namespace with prefix */
- str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_int_equal(1, xmlctx->ns.count);
- ns = (struct lyxml_ns *)xmlctx->ns.objs[0];
- assert_string_equal(ns->prefix, "nc");
- assert_string_equal(ns->uri, "urn");
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_string_equal("e", tree->schema->name);
+ lyd_free_all(tree);
}
static void
test_text(void **state)
{
const char *str;
- struct lyxml_ctx *xmlctx;
- struct ly_in *in;
-
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " anyxml e;"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
/* empty attribute value */
- str = "status);
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_true(!strncmp("", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 1);
- assert_int_equal(xmlctx->dynamic, 0);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ lyd_free_all(tree);
+ tree = NULL;
/* empty value but in single quotes */
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_true(!strncmp("", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 1);
- assert_int_equal(xmlctx->dynamic, 0);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ lyd_free_all(tree);
+ tree = NULL;
/* empty element content - only formating before defining child */
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(">\n ", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ELEMENT;
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp("\n ", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 1);
- assert_int_equal(xmlctx->dynamic, 0);
- ly_in_free(in, 0);
+ str = ">\n ";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
/* empty element content is invalid - missing content terminating character < */
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ELEM_CONTENT;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ELEM_CONTENT;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "xxx";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character sequence \"xxx\", expected element tag start ('<').", NULL, 1);
- ly_in_free(in, 0);
-
- lyxml_ctx_free(xmlctx);
- ly_log_location_revert(0, 0, 4);
+ UTEST_LOG_CTX_CLEAN;
/* valid strings */
- str = "€𠜎Øn \n<&"'> ROK";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp("€𠜎Øn \n<&\"\'> ROK", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 0);
- assert_int_equal(xmlctx->dynamic, 1);
- free((char *)xmlctx->value);
- ly_in_free(in, 0);
+ str = "€𠜎Øn \n<&"'> ROK";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ lyd_free_all(tree);
+ tree = NULL;
/* test using n-bytes UTF8 hexadecimal code points */
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'$¢€𐍈\'", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_true(!strncmp("$¢€𐍈", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 0);
- assert_int_equal(xmlctx->dynamic, 1);
- ly_in_free(in, 0);
+ str = "";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ lyd_free_all(tree);
+ tree = NULL;
/* CDATA value */
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("> &\"' ]]> ", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTR_CONTENT;
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_true(!strncmp(" special non-escaped chars <>&\"' ", xmlctx->value, xmlctx->value_len));
- assert_int_equal(xmlctx->ws_only, 0);
- assert_int_equal(xmlctx->dynamic, 1);
- free((char *)xmlctx->value);
- ly_in_free(in, 0);
+ str = " &\"' ]]> ";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ lyd_free_all(tree);
+ tree = NULL;
/* invalid characters in string */
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'R\'", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Entity reference \"&nonsense;\" not supported, only predefined references allowed.", NULL, 1);
- ly_in_free(in, 0);
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(">o122;", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ELEMENT;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "o122;";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, str, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Invalid character reference \"o122;\".", NULL, 1);
- ly_in_free(in, 0);
- assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in));
- xmlctx->in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "in = in;
- ly_log_location(NULL, NULL, in);
- xmlctx->status = LYXML_ATTRIBUTE;
- assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
+ str = "elements.count++;
- /* processing namespace definitions */
- assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, "nc", 2, strdup("urn:nc2")));
- assert_int_equal(3, xmlctx->ns.count);
- assert_int_not_equal(0, xmlctx->ns.size);
-
- ns = lyxml_ns_get(&xmlctx->ns, NULL, 0);
- assert_non_null(ns);
- assert_null(ns->prefix);
- assert_string_equal("urn:default", ns->uri);
-
- ns = lyxml_ns_get(&xmlctx->ns, "nc", 2);
- assert_non_null(ns);
- assert_string_equal("nc", ns->prefix);
- assert_string_equal("urn:nc2", ns->uri);
-
- /* simulate closing element2 */
- xmlctx->elements.count--;
- lyxml_ns_rm(xmlctx);
- assert_int_equal(2, xmlctx->ns.count);
-
- ns = lyxml_ns_get(&xmlctx->ns, "nc", 2);
- assert_non_null(ns);
- assert_string_equal("nc", ns->prefix);
- assert_string_equal("urn:nc1", ns->uri);
-
- /* close element1 */
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(0, xmlctx->ns.count);
-
- assert_null(lyxml_ns_get(&xmlctx->ns, "nc", 2));
- assert_null(lyxml_ns_get(&xmlctx->ns, NULL, 0));
-
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ struct lyd_node_opaq *opaq1, *opaq2;
+ struct lyd_attr *attr;
+ const char *xml =
+ "\n"
+ " \n"
+ "\n";
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, xml, LYD_XML,
+ LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, &tree));
+ assert_non_null(tree);
+
+ opaq1 = (struct lyd_node_opaq *)tree;
+ assert_string_equal("element1", opaq1->name.name);
+ assert_string_equal("urn:default", opaq1->name.module_ns);
+
+ attr = opaq1->attr;
+ assert_non_null(attr);
+ assert_string_equal("nc", attr->name.prefix);
+ assert_string_equal("urn:nc1", attr->name.module_ns);
+
+ assert_non_null(lyd_child(tree));
+ opaq2 = (struct lyd_node_opaq *)lyd_child(tree);
+ assert_string_equal("element2", opaq2->name.name);
+ assert_string_equal("urn:default", opaq2->name.module_ns);
+
+ attr = opaq2->attr;
+ assert_non_null(attr);
+ assert_string_equal("nc", attr->name.prefix);
+ assert_string_equal("urn:nc2", attr->name.module_ns);
+
+ lyd_free_all(tree);
}
static void
test_ns2(void **state)
{
- const char *str;
- struct lyxml_ctx *xmlctx;
- struct ly_in *in;
-
- /* opening element1 */
- str = "";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
-
- /* default namespace defined in parent element1 */
- assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, NULL, 0, strdup("urn:default")));
- assert_int_equal(1, xmlctx->ns.count);
- /* going into child element1 */
- /* simulate adding open element1 into context */
- xmlctx->elements.count++;
- /* no namespace defined, going out (first, simulate closing of so far open element) */
- xmlctx->elements.count--;
- lyxml_ns_rm(xmlctx);
- assert_int_equal(1, xmlctx->ns.count);
-
- /* nothing else, going out of the parent element1 */
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(0, xmlctx->ns.count);
-
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
-}
-
-static void
-test_simple_xml(void **state)
-{
- struct lyxml_ctx *xmlctx;
- struct ly_in *in;
- const char *test_input = " ";
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ struct lyd_node_opaq *parent, *child;
+ const char *xml =
+ "\n"
+ " \n"
+ "\n";
- assert_int_equal(LY_SUCCESS, ly_in_new_memory(test_input, &in));
- assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "attr1=\"value\"> ");
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, xml, LYD_XML,
+ LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, &tree));
+ assert_non_null(tree);
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "=\"value\"> ");
+ parent = (struct lyd_node_opaq *)tree;
+ assert_string_equal("element1", parent->name.name);
+ assert_string_equal("urn:default", parent->name.module_ns);
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "> ");
+ assert_non_null(lyd_child(tree));
+ child = (struct lyd_node_opaq *)lyd_child(tree);
+ assert_string_equal("element1", child->name.name);
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_string_equal(xmlctx->in->current, " ");
+ assert_string_equal("urn:default", child->name.module_ns);
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEMENT, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "attr2=\"value\" /> ");
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "=\"value\" /> ");
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
- assert_string_equal(xmlctx->in->current, " /> ");
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "/> ");
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
- assert_string_equal(xmlctx->in->current, " ");
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "");
-
- assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
- assert_int_equal(LYXML_END, xmlctx->status);
- assert_string_equal(xmlctx->in->current, "");
+ lyd_free_all(tree);
+}
- lyxml_ctx_free(xmlctx);
- ly_in_free(in, 0);
+static void
+test_simple_xml(void **state)
+{
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ struct lyd_node *tree = NULL;
+ const char *test_input = " value ";
+ const char *yang = "module test {"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " container elem1 {"
+ " leaf elem2 {"
+ " type string;"
+ " }"
+ " }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yang, LYS_IN_YANG, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, test_input, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_string_equal("elem1", tree->schema->name);
+ struct lyd_node *child = lyd_child(tree);
+
+ assert_non_null(child);
+ assert_string_equal("elem2", child->schema->name);
+ assert_string_equal("value", lyd_get_value(child));
+ lyd_free_all(tree);
+ tree = NULL;
}
int
diff --git a/tests/utests/basic/test_xpath.c b/tests/utests/basic/test_xpath.c
index 97c7287d12..79ba4445cc 100644
--- a/tests/utests/basic/test_xpath.c
+++ b/tests/utests/basic/test_xpath.c
@@ -19,7 +19,6 @@
#include "context.h"
#include "parser_data.h"
#include "set.h"
-#include "tests_config.h"
#include "tree_data.h"
#include "tree_schema.h"
diff --git a/tests/utests/basic/test_yanglib.c b/tests/utests/basic/test_yanglib.c
index 0349157f47..e7f6064b2f 100644
--- a/tests/utests/basic/test_yanglib.c
+++ b/tests/utests/basic/test_yanglib.c
@@ -20,7 +20,6 @@
#include "in.h"
#include "log.h"
#include "set.h"
-#include "tests_config.h"
#include "tree_data.h"
#include "tree_schema.h"
diff --git a/tests/utests/data/test_cbor.c b/tests/utests/data/test_cbor.c
new file mode 100644
index 0000000000..e8cd75eae8
--- /dev/null
+++ b/tests/utests/data/test_cbor.c
@@ -0,0 +1,380 @@
+/**
+ * @file test_cbor.c
+ * @author Juraj Budai
+ * @brief Cmocka tests for CBOR data format.
+ *
+ * Copyright (c) 2026 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 "in_internal.h"
+#include "parser_data.h"
+#include "printer_data.h"
+
+void **glob_state;
+
+static int
+setup(void **state)
+{
+ UTEST_SETUP;
+ glob_state = state;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "cbor-test", NULL, NULL));
+
+ return 0;
+}
+
+struct test_case {
+ const char *name;
+ const char *json;
+};
+
+static void
+test_node(void **state)
+{
+ struct lyd_node *tree;
+ char *buffer, *json;
+ struct ly_out *out;
+ size_t i;
+ uint32_t parse_opts;
+
+ const struct test_case tests[] = {
+ {"lf-str", "{\"cbor-test:lf-str\":\"example string\"}"},
+ {"lf-bool", "{\"cbor-test:lf-bool\":true}"},
+ {"lf-empty", "{\"cbor-test:lf-empty\":[null]}"},
+ {"lf-bin", "{\"cbor-test:lf-bin\":\"dGVzdA==\"}"},
+ {"lf-dec64", "{\"cbor-test:lf-dec64\":\"12.34\"}"},
+
+ {"lf-intg8", "{\"cbor-test:lf-intg8\":-128}"},
+ {"lf-intg16", "{\"cbor-test:lf-intg16\":-32768}"},
+ {"lf-intg32", "{\"cbor-test:lf-intg32\":-2147483648}"},
+ {"lf-intg64", "{\"cbor-test:lf-intg64\":\"-9223372036854775808\"}"},
+
+ {"lf-uintg8", "{\"cbor-test:lf-uintg8\":255}"},
+ {"lf-uintg16", "{\"cbor-test:lf-uintg16\":65535}"},
+ {"lf-uintg32", "{\"cbor-test:lf-uintg32\":4294967295}"},
+ {"lf-uintg64", "{\"cbor-test:lf-uintg64\":\"18446744073709551615\"}"},
+
+ {"lf-enum", "{\"cbor-test:lf-enum\":\"green\"}"},
+ {"lf-bits", "{\"cbor-test:lf-bits\":\"up running\"}"},
+ {"lf-idenref", "{\"cbor-test:lf-idenref\":\"ethernet\"}"},
+ {
+ "lf-inst-id",
+ "{"
+ "\"cbor-test:cont-root\":{\"lf-root-str\":\"example string\"},"
+ "\"cbor-test:lf-inst-id\":\"/cbor-test:cont-root/lf-root-str\""
+ "}"
+ },
+ {"lf-union-s", "{\"cbor-test:lf-union\":\"text\"}"},
+ {"lf-union-b", "{\"cbor-test:lf-union\":false}"},
+ {
+ "lf-lfref",
+ "{"
+ "\"cbor-test:lf-str\":\"referenced string\","
+ "\"cbor-test:lf-lfref\":\"referenced string\""
+ "}"
+ },
+ {
+ "augment",
+ "{"
+ "\"cbor-test:cont-root\":{"
+ "\"lf-root-str\":\"example string\","
+ "\"lf-augmented-str\":\"augmented string\""
+ "}"
+ "}"
+ },
+ {"anydata", "{\"cbor-test:anydata-payload\":{\"nested-key\":\"value\"}}"},
+ {"anydata-strict", "{\"cbor-test:anydata-payload\":{\"list-user\":[{\"key-id\":1,\"lf-name\":\"Alice\"}]}}"},
+ {"anyxml", "{\"cbor-test:anyxml-payload\":{\"xml-element\":\"text\"}}"},
+ {"ll-str", "{\"cbor-test:ll-str\":[\"val1\",\"val2\",\"val3\",\"val4\"]}"},
+ {"ll-intg32", "{\"cbor-test:ll-intg32\":[-30,10,20]}"},
+ {"list-one", "{\"cbor-test:list-user\":[{\"key-id\":1,\"lf-name\":\"Alice\"}]}"},
+ {"list-multi", "{\"cbor-test:list-user\":[{\"key-id\":1,\"lf-name\":\"Alice\"},{\"key-id\":2,\"lf-name\":\"Bob\"}]}"},
+ {"choice-tcp", "{\"cbor-test:lf-tcp-port\":8080}"},
+ {"choice-unix", "{\"cbor-test:lf-unix-socket\":\"/var/run/test.sock\"}"},
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
+ if (!strcmp(tests[i].name, "anydata-strict")) {
+ parse_opts = LYD_PARSE_STRICT | LYD_PARSE_ANYDATA_STRICT;
+ } else {
+ parse_opts = LYD_PARSE_STRICT;
+ }
+ CHECK_PARSE_LYD_PARAM(tests[i].json, LYD_JSON, parse_opts, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buffer, 0, &out));
+ assert_int_equal(LY_SUCCESS, lyd_print_all(out, tree, LYD_CBOR, 0));
+
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(((struct utest_context *)*state)->ctx, buffer,
+ (uint32_t)ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY, 0, &tree));
+
+ ly_out_free(out, NULL, 0);
+ free(buffer);
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_string_equal(json, tests[i].json);
+
+ free(json);
+ lyd_free_all(tree);
+ }
+}
+
+/**
+ * @brief Regression test: printing a (leaf-)list nested inside a list.
+ *
+ * The CBOR printer used to keep a single "currently open array" pointer in its
+ * context. When a leaf-list (or list) was nested inside a list, printing the
+ * inner array overwrote that pointer and then reset it to NULL, so the outer
+ * list pushed into a NULL array and the printer crashed (SIGSEGV in
+ * cbor_array_push()). This exercises exactly that structure and additionally
+ * checks the JSON round-trip fidelity.
+ */
+static void
+test_nested_list(void **state)
+{
+ struct lyd_node *tree;
+ char *buffer, *json;
+ struct ly_out *out;
+ size_t i;
+
+ const struct test_case tests[] = {
+ /* leaf-list nested inside a list */
+ {
+ "ll-in-list",
+ "{\"cbor-test:list-nested\":["
+ "{\"id\":\"a\",\"tags\":[\"t1\",\"t2\"]}"
+ "]}"
+ },
+ /* list nested inside a list, the inner list holding a leaf-list */
+ {
+ "list-in-list",
+ "{\"cbor-test:list-nested\":["
+ "{\"id\":\"a\",\"inner\":[{\"iid\":1,\"vals\":[10,20]},{\"iid\":2,\"vals\":[30]}]}"
+ "]}"
+ },
+ /* several outer instances mixing nested leaf-lists and lists */
+ {
+ "multi-nested",
+ "{\"cbor-test:list-nested\":["
+ "{\"id\":\"a\",\"tags\":[\"t1\",\"t2\"],\"inner\":[{\"iid\":1,\"vals\":[10,20]}]},"
+ "{\"id\":\"b\",\"inner\":[{\"iid\":3,\"vals\":[40]}]}"
+ "]}"
+ },
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
+ CHECK_PARSE_LYD_PARAM(tests[i].json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buffer, 0, &out));
+ /* this print call is what used to crash */
+ assert_int_equal(LY_SUCCESS, lyd_print_all(out, tree, LYD_CBOR, 0));
+
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(((struct utest_context *)*state)->ctx, buffer,
+ (uint32_t)ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY, 0, &tree));
+
+ ly_out_free(out, NULL, 0);
+ free(buffer);
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_string_equal(json, tests[i].json);
+
+ free(json);
+ lyd_free_all(tree);
+ }
+}
+
+static void
+test_operations(void **state)
+{
+ struct lyd_node *tree;
+ char *buffer, *json;
+ struct ly_out *out;
+ struct ly_in *in;
+ size_t i;
+
+ const struct test_case tests[] = {
+ {"rpc", "{\"cbor-test:rpc-reset\":{\"lf1\":true}}"},
+ {"notification", "{\"cbor-test:notif-alarm\":{\"lf-severity\":\"warning\",\"lf-message\":\"Something\"}}"},
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
+ enum lyd_type type = (strcmp(tests[i].name, "rpc") == 0) ? LYD_TYPE_RPC_YANG : LYD_TYPE_NOTIF_YANG;
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(tests[i].json, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(((struct utest_context *)*state)->ctx, NULL, in, LYD_JSON, type, 0, &tree, NULL));
+ ly_in_free(in, 0);
+
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buffer, 0, &out));
+ assert_int_equal(LY_SUCCESS, lyd_print_all(out, tree, LYD_CBOR, 0));
+
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(buffer, &in));
+ in->length = ly_out_printed(out);
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(((struct utest_context *)*state)->ctx, NULL, in, LYD_CBOR, type, 0, &tree, NULL));
+ ly_in_free(in, 0);
+
+ ly_out_free(out, NULL, 0);
+ free(buffer);
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_string_equal(json, tests[i].json);
+
+ free(json);
+ lyd_free_all(tree);
+ }
+}
+
+static LY_ERR
+test_ext_data_clb(const struct lysc_ext_instance *ext, const struct lyd_node *UNUSED(parent), void *user_data,
+ void **ext_data, ly_bool *ext_data_free)
+{
+ void **state = glob_state;
+ struct lyd_node *data = NULL;
+ const struct lys_module *sm_mod;
+
+ (void)ext;
+
+ if (user_data) {
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, NULL);
+ CHECK_PARSE_LYD_PARAM(user_data, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
+ sm_mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "ietf-yang-schema-mount");
+ assert_int_equal(LY_SUCCESS, lyd_validate_module(&data, sm_mod, 0, NULL));
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, user_data);
+ }
+
+ *ext_data = data;
+ *ext_data_free = 1;
+ return LY_SUCCESS;
+}
+
+static void
+test_schema_mount(void **state)
+{
+ struct lyd_node *tree = NULL;
+ char *cbor_buffer = NULL, *xml_buffer = NULL;
+ const char *ext_data, *input_xml;
+ struct ly_out *out_cbor = NULL;
+
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "base-mod", NULL, NULL));
+
+ ext_data =
+ ""
+ " "
+ " mount-set"
+ " "
+ " base-mod"
+ " urn:example:base-mod"
+ " "
+ " "
+ " "
+ " mount-schema"
+ " mount-set"
+ " "
+ " "
+ " ds:running"
+ " mount-schema"
+ " "
+ " 1"
+ ""
+ ""
+ " "
+ " cbor-test"
+ " "
+ " "
+ " "
+ "";
+
+ input_xml =
+ "\n"
+ " Hello\n"
+ " \n"
+ " Mounted value\n"
+ " \n"
+ "\n";
+
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, (void *)ext_data);
+
+ CHECK_PARSE_LYD_PARAM(input_xml, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&cbor_buffer, 0, &out_cbor));
+ assert_int_equal(LY_SUCCESS, lyd_print_all(out_cbor, tree, LYD_CBOR, 0));
+
+ lyd_free_all(tree);
+ tree = NULL;
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, cbor_buffer,
+ (uint32_t)ly_out_printed(out_cbor), LYD_CBOR, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, &tree));
+
+ ly_out_free(out_cbor, NULL, 0);
+ free(cbor_buffer);
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&xml_buffer, tree, LYD_XML, LYD_PRINT_SIBLINGS));
+ assert_string_equal(input_xml, xml_buffer);
+
+ free(xml_buffer);
+ lyd_free_all(tree);
+}
+
+static void
+test_opaque(void **state)
+{
+ struct lyd_node *tree;
+ char *buffer, *json;
+ const char *input_json;
+ struct ly_out *out;
+
+ input_json =
+ "{"
+ "\"cbor-test:cont-root\":{"
+ "\"lf-root-str\":\"Something\","
+ "\"nonexisting-element\":\"Random value\""
+ "}"
+ "}";
+
+ CHECK_PARSE_LYD_PARAM(input_json, LYD_JSON, LYD_PARSE_ONLY | LYD_PARSE_OPAQ, 0, LY_SUCCESS, tree);
+
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buffer, 0, &out));
+ assert_int_equal(LY_SUCCESS, lyd_print_all(out, tree, LYD_CBOR, 0));
+
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(((struct utest_context *)*state)->ctx, buffer,
+ (uint32_t)ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY | LYD_PARSE_OPAQ, 0, &tree));
+
+ ly_out_free(out, NULL, 0);
+ free(buffer);
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_string_equal(json, input_json);
+
+ free(json);
+ lyd_free_all(tree);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_node, setup),
+ UTEST(test_nested_list, setup),
+ UTEST(test_operations, setup),
+ UTEST(test_schema_mount, setup),
+ UTEST(test_opaque, setup),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index 8ec353df6e..215c5cf2cf 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -177,7 +177,7 @@ test_invalid(void **state)
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(model_1, lyd_child_no_keys(model_1), 0, &diff), LY_EINVAL);
CHECK_LOG_CTX("Invalid arguments - cannot create diff for unrelated data (lyd_diff()).", NULL, 0);
assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, NULL), LY_EINVAL);
@@ -315,7 +315,7 @@ test_empty_nested(void **state)
struct lyd_node *diff1;
- CHECK_PARSE_LYD_DIFF(NULL, lyd_child(model_1), 0, diff1);
+ CHECK_PARSE_LYD_DIFF(NULL, lyd_child_no_keys(model_1), 0, diff1);
CHECK_LYD_STRING(diff1,
"\n"
" 42\n"
@@ -323,7 +323,7 @@ test_empty_nested(void **state)
struct lyd_node *diff2;
- CHECK_PARSE_LYD_DIFF(lyd_child(model_1), NULL, 0, diff2);
+ CHECK_PARSE_LYD_DIFF(lyd_child_no_keys(model_1), NULL, 0, diff2);
CHECK_LYD_STRING(diff2,
"\n"
" 42\n"
diff --git a/tests/utests/data/test_lyb.c b/tests/utests/data/test_lyb.c
index 7f582db760..d53746dcc8 100644
--- a/tests/utests/data/test_lyb.c
+++ b/tests/utests/data/test_lyb.c
@@ -15,6 +15,7 @@
#include "utests.h"
#include "hash_table.h"
+#include "in_internal.h"
#include "libyang.h"
#define CHECK_PARSE_LYD(INPUT, OUT_NODE) \
@@ -28,12 +29,13 @@ check_print_parse(void **state, const char *data_xml, const struct ly_ctx *parse
{
struct lyd_node *tree_1, *tree_2 = NULL;
char *lyb_out = NULL;
+ uint32_t lyb_len;
LY_ERR r;
CHECK_PARSE_LYD(data_xml, tree_1);
- assert_int_equal(lyd_print_mem(&lyb_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
+ assert_int_equal(utest_lyd_print_mem_len(&lyb_out, &lyb_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
- r = lyd_parse_data_mem(parse_ctx, lyb_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2);
+ r = lyd_parse_data_mem_len(parse_ctx, lyb_out, lyb_len, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2);
if (expect_parse_success) {
assert_int_equal(r, LY_SUCCESS);
assert_non_null(tree_2);
@@ -466,6 +468,7 @@ test_opaq(void **state)
struct lyd_node *tree_1;
struct lyd_node *tree_2;
char *xml_out; /* tree_2 */
+ uint32_t xml_len;
LY_ERR rc;
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", NULL, nc_feats));
@@ -475,9 +478,11 @@ test_opaq(void **state)
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_SIBLINGS), 0);
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
ly_in_new_memory(xml_out, &in);
+ in->length = xml_len;
+ in->bounded = 1;
rc = lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_LYB, LYD_TYPE_RPC_YANG, LYD_PARSE_STRICT, &tree_2, NULL);
ly_in_free(in, 0);
assert_int_equal(rc, LY_SUCCESS);
@@ -2536,6 +2541,7 @@ test_shrink(void **state)
const char *mod, *data_xml;
struct lyd_node *tree1, *tree2;
char *lyb_out, *str;
+ uint32_t lyb_len;
mod =
"module mod { namespace \"urn:mod\"; prefix m;"
@@ -2551,9 +2557,9 @@ test_shrink(void **state)
/* non-shrinked */
data_xml = "";
CHECK_PARSE_LYD_PARAM(data_xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree1);
- assert_int_equal(lyd_print_mem(&lyb_out, tree1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, lyb_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT,
- 0, &tree2));
+ assert_int_equal(utest_lyd_print_mem_len(&lyb_out, &lyb_len, tree1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, lyb_out, lyb_len, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree2));
assert_non_null(tree2);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str, tree2, LYD_XML, LYD_PRINT_SIBLINGS | LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK));
@@ -2568,9 +2574,10 @@ test_shrink(void **state)
/* shrinked */
data_xml = "";
CHECK_PARSE_LYD_PARAM(data_xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree1);
- assert_int_equal(lyd_print_mem(&lyb_out, tree1, LYD_LYB, LYD_PRINT_SIBLINGS | LYD_PRINT_SHRINK), 0);
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, lyb_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT,
- 0, &tree2));
+ assert_int_equal(utest_lyd_print_mem_len(&lyb_out, &lyb_len, tree1, LYD_LYB,
+ LYD_PRINT_SIBLINGS | LYD_PRINT_SHRINK), 0);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, lyb_out, lyb_len, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree2));
assert_null(tree2);
free(lyb_out);
@@ -2785,6 +2792,7 @@ test_skip_module_check(void **state)
struct ly_ctx *ctx;
struct ly_in *in;
char *lyb_out;
+ uint32_t lyb_len;
struct lyd_node *tree1, *tree2;
const char *feats1[] = {"feat1", NULL};
const char *feats2[] = {"feat1", "feat2", NULL};
@@ -2818,14 +2826,14 @@ test_skip_module_check(void **state)
CHECK_PARSE_LYD(data_xml, tree1);
/* print it to LYB using UTEST_LYCTX (with mod_rev_1) */
- assert_int_equal(lyd_print_mem(&lyb_out, tree1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
+ assert_int_equal(utest_lyd_print_mem_len(&lyb_out, &lyb_len, tree1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
/* parse it in the new context (with mod_rev_2) - should fail due to revision mismatch */
- assert_int_not_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, lyb_out, LYD_LYB,
+ assert_int_not_equal(LY_SUCCESS, lyd_parse_data_mem_len(ctx, lyb_out, lyb_len, LYD_LYB,
LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree2));
/* parse it in the new context (with mod_rev_2) - should succeed when skipping module check */
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, lyb_out, LYD_LYB,
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(ctx, lyb_out, lyb_len, LYD_LYB,
LYD_PARSE_ONLY | LYD_PARSE_STRICT | LYD_PARSE_LYB_SKIP_MODULE_CHECK, 0, &tree2));
assert_non_null(tree2);
CHECK_LYD(tree1, tree2);
@@ -2864,14 +2872,14 @@ test_skip_module_check(void **state)
CHECK_PARSE_LYD(data_xml, tree1);
/* print it to LYB using UTEST_LYCTX (with feat1) */
- assert_int_equal(lyd_print_mem(&lyb_out, tree1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
+ assert_int_equal(utest_lyd_print_mem_len(&lyb_out, &lyb_len, tree1, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
/* parse it in the new context (with feat1 and feat2) - should fail due to feature mismatch */
- assert_int_not_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, lyb_out, LYD_LYB,
+ assert_int_not_equal(LY_SUCCESS, lyd_parse_data_mem_len(ctx, lyb_out, lyb_len, LYD_LYB,
LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree2));
/* parse it in the new context (with feat1 and feat2) - should succeed when skipping module check */
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, lyb_out, LYD_LYB,
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(ctx, lyb_out, lyb_len, LYD_LYB,
LYD_PARSE_ONLY | LYD_PARSE_STRICT | LYD_PARSE_LYB_SKIP_MODULE_CHECK, 0, &tree2));
assert_non_null(tree2);
CHECK_LYD(tree1, tree2);
@@ -2882,6 +2890,53 @@ test_skip_module_check(void **state)
ly_ctx_destroy(ctx);
}
+static void
+test_memory_bounds(void **state)
+{
+ const char *mod, *data_xml;
+ struct lyd_node *tree, *parsed = NULL;
+ char *lyb;
+ uint32_t lyb_len;
+
+ mod =
+ "module bounds {namespace urn:bounds;prefix b;"
+ "container cont {leaf value {type string;}}}";
+ UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL);
+
+ data_xml = "test";
+ CHECK_PARSE_LYD(data_xml, tree);
+ assert_int_equal(LY_SUCCESS, utest_lyd_print_mem_len(&lyb, &lyb_len, tree, LYD_LYB, LYD_PRINT_SIBLINGS));
+
+ /* Legacy unbounded memory input remains supported. */
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, lyb, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &parsed));
+ assert_non_null(parsed);
+ CHECK_LYD(tree, parsed);
+ lyd_free_all(parsed);
+ parsed = NULL;
+
+ /* Empty and truncated bounded inputs must fail without reading past their buffers. */
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem_len(UTEST_LYCTX, lyb, 0, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &parsed));
+ assert_null(parsed);
+ UTEST_LOG_CTX_CLEAN;
+
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem_len(UTEST_LYCTX, lyb, lyb_len - 1, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &parsed));
+ assert_null(parsed);
+ UTEST_LOG_CTX_CLEAN;
+
+ /* The complete bounded input still parses successfully. */
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, lyb, lyb_len, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &parsed));
+ assert_non_null(parsed);
+ CHECK_LYD(tree, parsed);
+
+ free(lyb);
+ lyd_free_all(tree);
+ lyd_free_all(parsed);
+}
+
int
main(void)
{
@@ -2899,6 +2954,7 @@ main(void)
UTEST(test_bits, setup),
UTEST(test_different_contexts, setup),
UTEST(test_skip_module_check, setup),
+ UTEST(test_memory_bounds),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/utests/data/test_merge.c b/tests/utests/data/test_merge.c
index 4a3663baf4..2f1985ad0f 100644
--- a/tests/utests/data/test_merge.c
+++ b/tests/utests/data/test_merge.c
@@ -654,8 +654,8 @@ test_dflt(void **state)
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);
+ assert_string_equal(lyd_child_no_keys(target)->prev->schema->name, "c");
+ assert_true(lyd_child_no_keys(target)->prev->flags & LYD_DEFAULT);
lyd_free_all(target);
lyd_free_all(source);
@@ -696,7 +696,7 @@ test_dflt2(void **state)
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);
+ assert_false(lyd_child_no_keys(target)->flags & LYD_DEFAULT);
lyd_free_all(target);
lyd_free_all(source);
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
index 936501325e..13f8d1fc0c 100644
--- a/tests/utests/data/test_new.c
+++ b/tests/utests/data/test_new.c
@@ -79,6 +79,9 @@ const char *schema_a = "module a {\n"
" }\n"
" }\n"
" }\n"
+ " leaf-list ll3 {\n"
+ " type uint8;\n"
+ " }\n"
" rpc oper {\n"
" input {\n"
" leaf param {\n"
@@ -281,6 +284,17 @@ test_path(void **state)
lyd_free_tree(root);
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:ll3", "1050", 0, 0, 0, NULL, NULL);
+ assert_int_equal(ret, LY_EVALID);
+ CHECK_LOG_CTX("Value \"1050\" is out of type uint8 min/max bounds.", "/a:ll3", 0);
+
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:ll3", "1050", 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_null(root->schema);
+
+ lyd_free_tree(root);
+
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, 0, NULL, NULL);
assert_int_equal(ret, LY_EVALID);
CHECK_LOG_CTX("Invalid type uint16 empty value.", "/a:foo", 0);
@@ -299,13 +313,13 @@ test_path(void **state)
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);
+ assert_non_null(lyd_child_no_keys(root));
+ assert_null(lyd_child_no_keys(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);
+ assert_non_null(lyd_child_no_keys(root)->next);
+ assert_null(lyd_child_no_keys(root)->next->schema);
lyd_free_tree(root);
@@ -526,6 +540,28 @@ test_path(void **state)
"}\n");
free(str);
lyd_free_siblings(root);
+
+ /* value with both ' and " */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:ll", "my-value with ' and \"", 0, LYD_VALHINT_STRING, 0, &root, NULL);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_SIBLINGS);
+ assert_string_equal(str,
+ "my-value with ' and \"\n");
+ free(str);
+ lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_SIBLINGS);
+ assert_string_equal(str,
+ "{\n"
+ " \"a:ll\": [\n"
+ " \"my-value with ' and \\\"\"\n"
+ " ]\n"
+ "}\n");
+ free(str);
+
+ str = lyd_path(root, LYD_PATH_STD, NULL, 0);
+ assert_null(str);
+ CHECK_LOG_CTX("Invalid value with both ' and \" characters, unable to put in quotes.", NULL, 0);
+ lyd_free_siblings(root);
}
static void
@@ -547,7 +583,7 @@ test_path_ext(void **state)
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_non_null(node = lyd_child_no_keys(root));
assert_string_equal(node->schema->name, "x");
assert_string_equal("xxx", lyd_get_value(node));
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index 7d88a6e79b..081ba18e47 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -20,8 +20,6 @@
#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
@@ -387,18 +385,28 @@ test_anydata_strict_validation(void **state)
const char *data_invalid;
const char *data_valid;
struct lyd_node *tree;
+ char *json;
- // no shcema defiend for "x" in the parsing context
+ /* no schema defiend for "x" in the parsing context */
data_without_schema = "{\"a:any\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
-
PARSER_CHECK_ERROR(data_without_schema, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"No module named \"x\" in the context.", "/a:any", 1);
data_invalid = "{\"a:any\":{\"a:fooA\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
-
PARSER_CHECK_ERROR(data_invalid, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Node \"fooA\" not found in the \"a\" module.", "/a:any", 1);
+ /* check print as well */
+ data_valid = "{\"a:any\":{\"a:l1\":[{\"d\":\"d\",\"a\":\"a\",\"c\":1,\"b\":\"b\"}]}}";
+ CHECK_PARSE_LYD(data_valid, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, tree, LYD_JSON, LYD_PRINT_SIBLINGS));
+ lyd_free_all(tree);
+ CHECK_PARSE_LYD(json, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree);
+ free(json);
+ assert_non_null(tree);
+ lyd_free_all(tree);
+
data_valid = "{\"a:any\":{\"foo\":\"default-val\"}}";
CHECK_PARSE_LYD(data_valid, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
@@ -799,14 +807,14 @@ test_rpc(void **state)
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;
+ node = lyd_child_no_keys(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)->child;
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);
+ node = lyd_child_no_keys(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;
@@ -912,13 +920,13 @@ test_reply(void **state)
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);
+ node = lyd_child_no_keys(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_SIBLINGS, "{\"a:al\":25}");
+ CHECK_LYD_STRING(lyd_child_no_keys(op), LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS, "{\"a:al\":25}");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS, "{\"a:c\":{\"act\":{\"al\":25}}}");
lyd_free_all(tree);
@@ -1013,7 +1021,7 @@ test_restconf_reply(void **state)
data = "{\"a:output\":{\"al\":25}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
- assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child(tree), in, LYD_JSON, LYD_TYPE_REPLY_RESTCONF,
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child_no_keys(tree), in, LYD_JSON, LYD_TYPE_REPLY_RESTCONF,
LYD_PARSE_STRICT, &envp, NULL));
ly_in_free(in, 0);
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index e0e3d2dca7..d99593ba0b 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -20,7 +20,6 @@
#include "out.h"
#include "parser_data.h"
#include "printer_data.h"
-#include "tree_data_internal.h"
#include "tree_schema.h"
static int
@@ -476,7 +475,7 @@ test_rpc(void **state)
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;
+ node = lyd_child_no_keys(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);
@@ -484,7 +483,7 @@ test_rpc(void **state)
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);
+ node = lyd_child_no_keys(node);
/* z has no value */
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 1, "");
node = node->parent->next;
@@ -617,13 +616,13 @@ test_reply(void **state)
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);
+ node = lyd_child_no_keys(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_SIBLINGS, "25\n");
+ CHECK_LYD_STRING(lyd_child_no_keys(op), LYD_PRINT_SIBLINGS, "25\n");
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
@@ -677,7 +676,7 @@ test_netconf_rpc(void **state)
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;
+ node = lyd_child_no_keys(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);
@@ -685,7 +684,7 @@ test_netconf_rpc(void **state)
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);
+ node = lyd_child_no_keys(node);
/* z has no value */
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 1, "");
node = node->parent->next;
@@ -766,7 +765,7 @@ test_netconf_action(void **state)
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, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child_no_keys(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,
@@ -824,7 +823,7 @@ test_netconf_reply_or_notification(void **state)
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,
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child_no_keys(tree), 0, 0, LY_VALUE_XML, "eventTime", 0, 0, 0, 0,
"2010-12-06T08:00:01Z");
assert_non_null(op2);
@@ -886,7 +885,7 @@ test_netconf_reply_or_notification(void **state)
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_NODE_OPAQ((struct lyd_node_opaq *)lyd_child_no_keys(tree), 0, 0, LY_VALUE_XML, "ok", 0, 0, 0, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SIBLINGS, data);
@@ -970,7 +969,7 @@ test_restconf_reply(void **state)
data = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
- assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child(tree), in, LYD_XML, LYD_TYPE_REPLY_RESTCONF,
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child_no_keys(tree), in, LYD_XML, LYD_TYPE_REPLY_RESTCONF,
LYD_PARSE_STRICT, &envp, NULL));
ly_in_free(in, 0);
@@ -1009,7 +1008,7 @@ test_filter_attributes(void **state)
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);
+ node = lyd_child_no_keys(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);
diff --git a/tests/utests/data/test_printer_json.c b/tests/utests/data/test_printer_json.c
index 2f648019b1..da38dcfe55 100644
--- a/tests/utests/data/test_printer_json.c
+++ b/tests/utests/data/test_printer_json.c
@@ -148,7 +148,7 @@ test_no_json_nested_prefix(void **state)
CHECK_STRING(buffer, "{\"schema2:a\":{\"b\":{\"c\":\"dflt\"}}}");
free(buffer);
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, lyd_child(tree), LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WD_ALL |
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, lyd_child_no_keys(tree), LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WD_ALL |
LYD_PRINT_JSON_NO_NESTED_PREFIX));
CHECK_STRING(buffer, "{\"b\":{\"c\":\"dflt\"}}");
free(buffer);
diff --git a/tests/utests/data/test_printer_xml.c b/tests/utests/data/test_printer_xml.c
index e8f416ca87..9fa901b25c 100644
--- a/tests/utests/data/test_printer_xml.c
+++ b/tests/utests/data/test_printer_xml.c
@@ -20,7 +20,6 @@
#include "out.h"
#include "parser_data.h"
#include "printer_data.h"
-#include "tests_config.h"
#include "tree_schema.h"
static int
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
index 624a9488d7..4f2f89e80b 100644
--- a/tests/utests/data/test_tree_data.c
+++ b/tests/utests/data/test_tree_data.c
@@ -15,9 +15,6 @@
#include "utests.h"
#include "libyang.h"
-#include "ly_common.h"
-#include "path.h"
-#include "xpath.h"
static int
setup(void **state)
@@ -233,7 +230,7 @@ test_compare_diff_ctx(void **state)
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));
+ assert_int_equal(LY_ENOT, lyd_compare_single(lyd_child_no_keys(lyd_child_no_keys(tree1)), lyd_child_no_keys(lyd_child_no_keys(tree2)), 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
@@ -337,7 +334,7 @@ test_dup(void **state)
data = "b";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
- assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), NULL, LYD_DUP_WITH_PARENTS, &tree2));
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child_no_keys(lyd_child_no_keys(tree1->next)), NULL, LYD_DUP_WITH_PARENTS, &tree2));
int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM;
CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "x", 1, LYS_LEAF, 1, 0, NULL, 0);
@@ -377,8 +374,6 @@ 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 =
""
@@ -394,11 +389,7 @@ test_target(void **state)
"";
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, exp, LY_PATH_OPER_INPUT,
- LY_PATH_TARGET_SINGLE, 1, LY_VALUE_JSON, NULL, &path));
- assert_int_equal(LY_SUCCESS, lyd_find_target(path, tree, (struct lyd_node **)&term));
+ assert_int_equal(LY_SUCCESS, lyd_find_path(tree, path_str, 0, (struct lyd_node **)&term));
const int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM | LYS_ORDBY_USER;
@@ -407,8 +398,6 @@ test_target(void **state)
assert_string_equal(lyd_get_value(term->prev), "b");
lyd_free_all(tree);
- ly_path_free(path);
- lyxp_expr_free(exp);
}
static void
@@ -541,26 +530,41 @@ test_data_hash(void **state)
}
static void
-test_lyxp_vars(void **UNUSED(state))
+test_lyxp_vars(void **state)
{
- struct lyxp_var *vars;
+ struct lyxp_var *vars = NULL;
+ struct lyd_node *tree = NULL;
+ struct ly_set *set = NULL;
+ const char *dummy_yang =
+ "module dummy {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:dummy\";\n"
+ " prefix d;\n"
+ " leaf target-node { type string; }\n"
+ " leaf other-node { type string; }\n"
+ "}";
/* 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");
+ /* Check correct value and name*/
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, dummy_yang, LYS_IN_YANG, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/dummy:target-node", "match-me", 0, &tree));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(tree, UTEST_LYCTX, "/dummy:other-node", "ignore-me", 0, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, NULL));
+
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "my_var", "'match-me'"));
+
+ assert_int_equal(LY_SUCCESS, lyd_find_xpath2(tree, "/dummy:target-node[. = $my_var]", vars, &set));
+ assert_non_null(set);
+ assert_int_equal(set->count, 1);
+ ly_set_free(set, NULL);
+ lyd_free_all(tree);
lyxp_vars_free(vars);
vars = NULL;
@@ -569,12 +573,6 @@ test_lyxp_vars(void **UNUSED(state))
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;
@@ -582,10 +580,7 @@ test_lyxp_vars(void **UNUSED(state))
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");
+ assert_int_equal(LY_ARRAY_COUNT(vars), 2);
lyxp_vars_free(vars);
vars = NULL;
}
diff --git a/tests/utests/data/test_tree_data_sorted.c b/tests/utests/data/test_tree_data_sorted.c
index 12967f1e36..1c4f310539 100644
--- a/tests/utests/data/test_tree_data_sorted.c
+++ b/tests/utests/data/test_tree_data_sorted.c
@@ -15,9 +15,6 @@
#include "utests.h"
#include "libyang.h"
-#include "ly_common.h"
-#include "tree_data_internal.h"
-#include "tree_data_sorted.h"
#define META_NAME "lyds_tree"
@@ -52,9 +49,12 @@ test_insert_top_level_list(void **state)
assert_int_equal(lyd_insert_sibling(first, node, NULL), LY_SUCCESS);
assert_true(first->next && first->prev && first->prev->meta);
assert_string_equal(first->prev->meta->name, META_NAME);
- assert_string_equal(lyd_get_value(lyd_child(first->prev)), "1");
- assert_string_equal(lyd_get_value(lyd_child(first)), "2");
- assert_string_equal(lyd_get_value(lyd_child(first->next)), "3");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first->prev, "k", 0, &node));
+ assert_string_equal(lyd_get_value(node), "1");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first, "k", 0, &node));
+ assert_string_equal(lyd_get_value(node), "2");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first->next, "k", 0, &node));
+ assert_string_equal(lyd_get_value(node), "3");
lyd_free_all(first);
}
@@ -87,7 +87,7 @@ test_insert_cont_list(void **state)
{
const char *schema;
struct lys_module *mod;
- struct lyd_node *cont, *node;
+ struct lyd_node *cont, *node, *key_node;
schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;revision 2014-05-08;"
"container cn { list lst {key \"k\"; leaf k {type uint32;}}}}";
@@ -97,12 +97,16 @@ test_insert_cont_list(void **state)
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "2"), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "1"), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "3"), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->meta && node->next && node->next->next);
assert_string_equal(node->meta->name, META_NAME);
- assert_string_equal(lyd_get_value(lyd_child(node)), "1");
- assert_string_equal(lyd_get_value(lyd_child(node->next)), "2");
- assert_string_equal(lyd_get_value(lyd_child(node->next->next)), "3");
+
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "1");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "2");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node->next->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "3");
lyd_free_all(cont);
}
@@ -121,7 +125,7 @@ test_insert_cont_leaflist(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->next->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "1");
@@ -152,7 +156,7 @@ test_dup_sort(void **state)
assert_int_equal(lyd_new_list(cont2, NULL, "lst", 0, NULL, "3"), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont2, NULL, "lst", 0, NULL, "8"), LY_SUCCESS);
- assert_int_equal(lyd_dup_siblings(lyd_child(cont2), cont, 0, NULL), LY_SUCCESS);
+ assert_int_equal(lyd_dup_siblings(lyd_child_no_keys(cont2), cont, 0, NULL), LY_SUCCESS);
lyd_print_mem(&str, cont, LYD_XML, 0);
assert_string_equal(str,
"\n"
@@ -216,7 +220,7 @@ test_ordered_by_user(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta);
assert_string_equal(lyd_get_value(node), "2");
assert_string_equal(lyd_get_value(node->next), "1");
@@ -239,13 +243,13 @@ test_remove(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->next->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
deleted = node;
lyd_unlink_tree(deleted);
lyd_free_tree(deleted);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "2");
@@ -257,13 +261,13 @@ test_remove(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->next->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
deleted = node->next;
lyd_unlink_tree(deleted);
lyd_free_tree(deleted);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "1");
@@ -275,13 +279,13 @@ test_remove(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->next->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
deleted = node->next->next;
lyd_unlink_tree(deleted);
lyd_free_tree(deleted);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "1");
@@ -291,12 +295,12 @@ test_remove(void **state)
/* Remove all */
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_non_null(node);
deleted = node;
lyd_unlink_tree(deleted);
lyd_free_tree(deleted);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_null(node);
lyd_free_all(cont);
}
@@ -316,19 +320,19 @@ test_remove_then_insert(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
deleted = node;
lyd_unlink_tree(deleted);
lyd_free_tree(deleted);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_non_null(node->meta);
assert_string_equal(node->meta->name, META_NAME);
/* insert last */
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "2");
@@ -336,7 +340,7 @@ test_remove_then_insert(void **state)
/* insert first */
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "1");
@@ -395,12 +399,12 @@ test_insert_before_anchor(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "lln", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta);
assert_string_equal(lyd_get_value(node), "1");
assert_int_equal(lyd_new_term(cont, mod, "llm", "2", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta && node->next);
assert_string_equal(lyd_get_value(node), "2");
assert_string_equal(lyd_get_value(node->next), "1");
@@ -429,12 +433,12 @@ test_insert_after_anchor(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "llm", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta);
assert_string_equal(lyd_get_value(node), "1");
assert_int_equal(lyd_new_term(cont, mod, "lln", "2", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta && node->next);
assert_string_equal(lyd_get_value(node), "1");
assert_string_equal(lyd_get_value(node->next), "2");
@@ -455,12 +459,12 @@ test_insert_same_values_leaflist(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- n1 = lyd_child(cont);
+ n1 = lyd_child_no_keys(cont);
assert_true(n1 && !n1->meta);
assert_string_equal(lyd_get_value(n1), "1");
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- n2 = lyd_child(cont);
+ n2 = lyd_child_no_keys(cont);
assert_true(n2 && n2->meta && n2->next);
assert_string_equal(n2->meta->name, META_NAME);
assert_string_equal(lyd_get_value(n2), "1");
@@ -475,7 +479,7 @@ test_insert_same_values_list(void **state)
{
const char *schema;
struct lys_module *mod;
- struct lyd_node *cont, *n1, *n2;
+ struct lyd_node *cont, *n1, *n2, *key_node;
schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;revision 2014-05-08;"
"container cn { list lst {key \"k\"; leaf k {type uint32;}}}}";
@@ -484,16 +488,19 @@ test_insert_same_values_list(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "1"), LY_SUCCESS);
- n1 = lyd_child(cont);
+ n1 = lyd_child_no_keys(cont);
assert_true(n1 && !n1->meta);
- assert_string_equal(lyd_get_value(lyd_child(n1)), "1");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(n1, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "1");
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "1"), LY_SUCCESS);
- n2 = lyd_child(cont);
+ n2 = lyd_child_no_keys(cont);
assert_true(n2 && n2->meta);
assert_string_equal(n2->meta->name, META_NAME);
- assert_string_equal(lyd_get_value(lyd_child(n2)), "1");
- assert_string_equal(lyd_get_value(lyd_child(n2->next)), "1");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(n2, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "1");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(n2->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "1");
assert_ptr_equal(n1, n2);
lyd_free_all(cont);
@@ -519,22 +526,22 @@ test_remove_same_values_leaflist(void **state)
/* remove second node */
lyd_free_tree(n2);
- child = lyd_child(cont);
+ child = lyd_child_no_keys(cont);
assert_true((child == n1) && (child->next == n3) && (child->next->next == n4) && (child->next->next->next == n5));
/* remove first node */
lyd_free_tree(n1);
- child = lyd_child(cont);
+ child = lyd_child_no_keys(cont);
assert_true((child == n3) && (child->next == n4) && (child->next->next == n5));
/* remove fifth node */
lyd_free_tree(n5);
- child = lyd_child(cont);
+ child = lyd_child_no_keys(cont);
assert_true((child == n3) && (child->next == n4));
/* remove fourth node */
lyd_free_tree(n4);
- child = lyd_child(cont);
+ child = lyd_child_no_keys(cont);
assert_true(child == n3);
lyd_free_all(cont);
@@ -557,10 +564,10 @@ test_insert_keyless_list(void **state)
assert_int_equal(lyd_new_term(lst, mod, "lf", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, &lst), LY_SUCCESS);
assert_int_equal(lyd_new_term(lst, mod, "lf", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta && node->next);
- assert_string_equal(lyd_get_value(lyd_child(node)), "2");
- assert_string_equal(lyd_get_value(lyd_child(node->next)), "1");
+ assert_string_equal(lyd_get_value(lyd_child_no_keys(node)), "2");
+ assert_string_equal(lyd_get_value(lyd_child_no_keys(node->next)), "1");
lyd_free_all(cont);
}
@@ -577,11 +584,11 @@ test_leaflist_default(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && !node->meta);
assert_string_equal(lyd_get_value(node), "2");
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont);
+ node = lyd_child_no_keys(cont);
assert_true(node && node->next && node->meta);
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "1");
@@ -604,11 +611,11 @@ test_unlink_then_insert(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
lyd_unlink_tree(first);
- second = lyd_child(cont);
+ second = lyd_child_no_keys(cont);
lyd_unlink_tree(second);
- third = lyd_child(cont);
+ third = lyd_child_no_keys(cont);
assert_true(third && third->meta && !first->meta && !second->meta);
assert_string_equal(third->meta->name, META_NAME);
@@ -623,17 +630,17 @@ test_unlink_then_insert(void **state)
assert_string_equal(first->meta->name, META_NAME);
/* check the order */
- assert_ptr_equal(lyd_child(cont), first);
- first = lyd_child(cont);
+ assert_ptr_equal(lyd_child_no_keys(cont), first);
+ first = lyd_child_no_keys(cont);
assert_string_equal(lyd_get_value(first), "1");
assert_string_equal(lyd_get_value(first->next), "2");
assert_string_equal(lyd_get_value(first->next->next), "3");
/* unlink all nodes */
- lyd_unlink_tree(lyd_child(cont));
- lyd_unlink_tree(lyd_child(cont));
- lyd_unlink_tree(lyd_child(cont));
- assert_null(lyd_child(cont));
+ lyd_unlink_tree(lyd_child_no_keys(cont));
+ lyd_unlink_tree(lyd_child_no_keys(cont));
+ lyd_unlink_tree(lyd_child_no_keys(cont));
+ assert_null(lyd_child_no_keys(cont));
assert_true(!first->meta && !second->meta && third->meta && get_rbt(third->meta));
assert_string_equal(third->meta->name, META_NAME);
@@ -662,10 +669,10 @@ test_change_term(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
/* change node which has no meta */
- node = lyd_child(cont)->next;
+ node = lyd_child_no_keys(cont)->next;
assert_int_equal(lyd_change_term(node, "5"), LY_SUCCESS);
assert_string_equal(lyd_get_value(node), "5");
assert_true(first && first->meta && first->next && first->next->next);
@@ -676,7 +683,7 @@ test_change_term(void **state)
/* change node which has meta */
assert_int_equal(lyd_change_term(first, "6"), LY_SUCCESS);
assert_string_equal(lyd_get_value(first), "6");
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
assert_true(first && first->meta && first->next && first->next->next);
assert_string_equal(lyd_get_value(first), "3");
assert_string_equal(lyd_get_value(first->next), "5");
@@ -690,7 +697,7 @@ test_change_key(void **state)
{
const char *schema;
struct lys_module *mod;
- struct lyd_node *cont, *first, *node;
+ struct lyd_node *cont, *first, *node, *key_node;
schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;revision 2014-05-08;"
"container cn { list lst {key \"k\"; leaf k {type uint32;}}}}";
@@ -700,25 +707,33 @@ test_change_key(void **state)
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "1"), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "2"), LY_SUCCESS);
assert_int_equal(lyd_new_list(cont, mod, "lst", 0, NULL, "3"), LY_SUCCESS);
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
/* change node which has no meta */
- node = lyd_child(cont)->next;
- assert_int_equal(lyd_change_term(lyd_child(node), "5"), LY_SUCCESS);
- assert_string_equal(lyd_get_value(lyd_child(node)), "5");
+ node = first->next;
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node, "k", 0, &key_node));
+ assert_int_equal(lyd_change_term(key_node, "5"), LY_SUCCESS);
+ assert_string_equal(lyd_get_value(key_node), "5");
assert_true(first && first->meta && first->next && first->next->next);
- assert_string_equal(lyd_get_value(lyd_child(first)), "1");
- assert_string_equal(lyd_get_value(lyd_child(first->next)), "3");
- assert_string_equal(lyd_get_value(lyd_child(first->next->next)), "5");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "1");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "3");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first->next->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "5");
/* change node which has meta */
- assert_int_equal(lyd_change_term(lyd_child(first), "6"), LY_SUCCESS);
- assert_string_equal(lyd_get_value(lyd_child(first)), "6");
- first = lyd_child(cont);
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first, "k", 0, &key_node));
+ assert_int_equal(lyd_change_term(key_node, "6"), LY_SUCCESS);
+ assert_string_equal(lyd_get_value(key_node), "6");
+ first = lyd_child_no_keys(cont);
assert_true(first && first->meta && first->next && first->next->next);
- assert_string_equal(lyd_get_value(lyd_child(first)), "3");
- assert_string_equal(lyd_get_value(lyd_child(first->next)), "5");
- assert_string_equal(lyd_get_value(lyd_child(first->next->next)), "6");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "3");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "5");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(first->next->next, "k", 0, &key_node));
+ assert_string_equal(lyd_get_value(key_node), "6");
lyd_free_all(cont);
}
@@ -754,10 +769,11 @@ test_lyd_dup_meta(void **state)
assert_int_equal(ly_in_new_memory(schema, &UTEST_IN), LY_SUCCESS);
assert_int_equal(lys_parse(ctx2, UTEST_IN, LYS_IN_YANG, NULL, &mod2), LY_SUCCESS);
ly_in_free(UTEST_IN, 0), UTEST_IN = NULL;
- assert_int_equal(lyd_new_term(NULL, mod2, "ll", "1", 0, &par2), LY_SUCCESS);
- assert_int_equal(lyd_dup_meta_single_to_ctx(ctx2, node->meta, par2, &meta2), LY_SUCCESS);
+ assert_int_equal(lyd_dup_single_to_ctx(node, ctx2, NULL, 0, &par2), LY_SUCCESS);
+ meta2 = par2->meta;
+ assert_non_null(meta2);
assert_ptr_not_equal(node->meta->annotation, meta2->annotation);
- assert_null(get_rbt(meta2));
+ assert_ptr_equal(ctx2, meta2->annotation->module->ctx);
lyd_free_all(par2);
ly_ctx_destroy(ctx2);
@@ -780,7 +796,7 @@ test_insert_into_duplicate(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
/* create duplicate */
assert_int_equal(lyd_dup_single(cont, NULL, LYD_DUP_RECURSIVE, &dup), LY_SUCCESS);
- node = lyd_child(dup);
+ node = lyd_child_no_keys(dup);
assert_true(node && node->next && !get_rbt(node->meta));
assert_string_equal(node->meta->name, META_NAME);
/* insert into duplicate */
@@ -809,10 +825,10 @@ test_option_dup_no_meta(void **state)
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "3", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_dup_siblings(cont, NULL, LYD_DUP_NO_META | LYD_DUP_RECURSIVE, &dup), LY_SUCCESS);
- node = lyd_child(dup);
+ node = lyd_child_no_keys(dup);
assert_true(node && !node->meta);
assert_int_equal(lyd_new_term(dup, mod, "ll", "1", 0, NULL), LY_SUCCESS);
- node = lyd_child(dup);
+ node = lyd_child_no_keys(dup);
assert_non_null(node->meta && get_rbt(node->meta));
assert_string_equal(node->meta->name, META_NAME);
assert_string_equal(lyd_get_value(node), "1");
@@ -1074,9 +1090,9 @@ test_merge_siblings_destruct(void **state)
assert_true(dst && !dst->meta);
data = "{\"b:cont\": {\"ll\":[1,2,3]} }";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, src);
- assert_true(src && lyd_child(src)->meta);
+ assert_true(src && lyd_child_no_keys(src)->meta);
assert_int_equal(lyd_merge_siblings(&dst, src, LYD_MERGE_DESTRUCT), LY_SUCCESS);
- first = lyd_child(dst);
+ first = lyd_child_no_keys(dst);
assert_true(first->meta && get_rbt(first->meta));
assert_string_equal(first->meta->name, META_NAME);
assert_string_equal(lyd_get_value(first), "1");
@@ -1090,6 +1106,7 @@ test_parse_data(void **state)
{
const char *schema, *data;
char *lyb_out;
+ uint32_t lyb_len;
struct lys_module *mod;
struct lyd_node *tree, *tree2;
@@ -1115,9 +1132,9 @@ test_parse_data(void **state)
/* data tree is used in the next check */
/* lyb */
- assert_int_equal(lyd_print_mem(&lyb_out, tree, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
- assert_int_equal(lyd_parse_data_mem(UTEST_LYCTX, lyb_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT,
- 0, &tree2), LY_SUCCESS);
+ assert_int_equal(utest_lyd_print_mem_len(&lyb_out, &lyb_len, tree, LYD_LYB, LYD_PRINT_SIBLINGS), 0);
+ assert_int_equal(lyd_parse_data_mem_len(UTEST_LYCTX, lyb_out, lyb_len, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree2), LY_SUCCESS);
assert_true(tree2 && tree2->meta && tree2->next);
assert_string_equal(tree2->meta->name, META_NAME);
CHECK_LYD_VALUE(((struct lyd_node_term *)tree2)->value, UINT32, "1", 1);
@@ -1227,14 +1244,14 @@ test_manipulation_of_many_nodes(void **state)
}
/* sort check */
- prev = lyd_child(cont);
+ prev = lyd_child_no_keys(cont);
LY_LIST_FOR(prev->next, iter) {
assert_true(lyd_get_value(prev)[0] <= lyd_get_value(iter)[0]);
prev = iter;
}
/* remove every even node */
- LY_LIST_FOR(lyd_child(cont), iter) {
+ LY_LIST_FOR(lyd_child_no_keys(cont), iter) {
node = iter->next;
lyd_unlink_tree(node);
lyd_free_tree(node);
@@ -1242,7 +1259,7 @@ test_manipulation_of_many_nodes(void **state)
data_len /= 2;
/* sort check */
- prev = lyd_child(cont);
+ prev = lyd_child_no_keys(cont);
i = 1;
LY_LIST_FOR(prev->next, iter) {
assert_true(lyd_get_value(prev)[0] <= lyd_get_value(iter)[0]);
@@ -1254,27 +1271,6 @@ test_manipulation_of_many_nodes(void **state)
lyd_free_all(cont);
}
-static void
-test_lyds_free_metadata(void **state)
-{
- const char *schema;
- struct lys_module *mod;
- struct lyd_node *first, *node;
-
- schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;revision 2014-05-08;"
- "leaf-list ll {type uint32;}}";
- UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
-
- assert_int_equal(lyd_new_term(NULL, mod, "ll", "1", 0, &first), LY_SUCCESS);
- assert_int_equal(lyd_new_term(NULL, mod, "ll", "2", 0, &node), LY_SUCCESS);
- assert_int_equal(lyd_insert_sibling(first, node, NULL), LY_SUCCESS);
- lyds_free_metadata(first);
- assert_null(first->meta);
- assert_null(node->meta);
-
- lyd_free_all(first);
-}
-
static void
test_move_whole_list(void **state)
{
@@ -1304,14 +1300,14 @@ test_move_whole_list(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &src), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "1", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "2", 0, &node), LY_SUCCESS);
- first = lyd_child(src);
+ first = lyd_child_no_keys(src);
assert_int_equal(lyd_unlink_siblings(first), LY_SUCCESS);
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &dst), LY_SUCCESS);
assert_int_equal(lyd_insert_child(dst, first), LY_SUCCESS);
- first = lyd_child(dst);
+ first = lyd_child_no_keys(dst);
assert_true(first && first->meta && get_rbt(first->meta) && first->next);
assert_string_equal(first->meta->name, META_NAME);
- assert_true(!lyd_child(src));
+ assert_true(!lyd_child_no_keys(src));
lyd_free_all(src);
lyd_free_all(dst);
@@ -1319,15 +1315,15 @@ test_move_whole_list(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &src), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "1", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "2", 0, &node), LY_SUCCESS);
- first = lyd_child(src);
- assert_int_equal(lyd_unlink_siblings(lyd_child(src)), LY_SUCCESS);
+ first = lyd_child_no_keys(src);
+ assert_int_equal(lyd_unlink_siblings(lyd_child_no_keys(src)), LY_SUCCESS);
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &dst), LY_SUCCESS);
assert_int_equal(lyd_new_term(dst, mod, "tail", "a", 0, &node), LY_SUCCESS);
- assert_int_equal(lyd_insert_sibling(lyd_child(dst), first, NULL), LY_SUCCESS);
- first = lyd_child(dst);
+ assert_int_equal(lyd_insert_sibling(lyd_child_no_keys(dst), first, NULL), LY_SUCCESS);
+ first = lyd_child_no_keys(dst);
assert_true(first && first->meta && get_rbt(first->meta) && first->next);
assert_string_equal(first->meta->name, META_NAME);
- assert_true(!lyd_child(src));
+ assert_true(!lyd_child_no_keys(src));
lyd_free_all(src);
lyd_free_all(dst);
@@ -1335,17 +1331,17 @@ test_move_whole_list(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &src), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "1", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "2", 0, &node), LY_SUCCESS);
- first = lyd_child(src);
- assert_int_equal(lyd_unlink_siblings(lyd_child(src)), LY_SUCCESS);
+ first = lyd_child_no_keys(src);
+ assert_int_equal(lyd_unlink_siblings(lyd_child_no_keys(src)), LY_SUCCESS);
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &dst), LY_SUCCESS);
assert_int_equal(lyd_new_term(dst, mod, "head", "a", 0, &node), LY_SUCCESS);
- assert_int_equal(lyd_insert_sibling(lyd_child(dst), first, NULL), LY_SUCCESS);
- first = lyd_child(dst);
+ assert_int_equal(lyd_insert_sibling(lyd_child_no_keys(dst), first, NULL), LY_SUCCESS);
+ first = lyd_child_no_keys(dst);
assert_true(first && first->next);
node = first->next;
assert_true(node && node->meta && get_rbt(node->meta) && node->next);
assert_string_equal(node->meta->name, META_NAME);
- assert_true(!lyd_child(src));
+ assert_true(!lyd_child_no_keys(src));
lyd_free_all(src);
lyd_free_all(dst);
}
@@ -1385,8 +1381,8 @@ test_move_part_list(void **state)
assert_int_equal(lyd_new_term(src, mod, "ll", "1", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "2", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "3", 0, &node), LY_SUCCESS);
- assert_int_equal(lyd_insert_sibling(NULL, lyd_child(src), &dst), LY_SUCCESS);
- first = lyd_child(src);
+ assert_int_equal(lyd_insert_sibling(NULL, lyd_child_no_keys(src), &dst), LY_SUCCESS);
+ first = lyd_child_no_keys(src);
assert_true(first && first->meta && get_rbt(first->meta) && first->next);
assert_string_equal(first->meta->name, META_NAME);
assert_true(dst && !dst->meta && !dst->next);
@@ -1399,11 +1395,11 @@ test_move_part_list(void **state)
assert_int_equal(lyd_new_term(src, mod, "ll", "2", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_term(src, mod, "ll", "3", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &dst), LY_SUCCESS);
- assert_int_equal(lyd_insert_child(dst, lyd_child(src)), LY_SUCCESS);
- first = lyd_child(src);
+ assert_int_equal(lyd_insert_child(dst, lyd_child_no_keys(src)), LY_SUCCESS);
+ first = lyd_child_no_keys(src);
assert_true(first && first->meta && get_rbt(first->meta) && first->next);
assert_string_equal(first->meta->name, META_NAME);
- first = lyd_child(dst);
+ first = lyd_child_no_keys(dst);
assert_true(first && !first->meta);
lyd_free_all(src);
lyd_free_all(dst);
@@ -1415,11 +1411,11 @@ test_move_part_list(void **state)
assert_int_equal(lyd_new_term(src, mod, "ll", "3", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &dst), LY_SUCCESS);
assert_int_equal(lyd_new_term(dst, mod, "tail", "a", 0, &node), LY_SUCCESS);
- assert_int_equal(lyd_insert_sibling(lyd_child(dst), lyd_child(src), NULL), LY_SUCCESS);
- first = lyd_child(src);
+ assert_int_equal(lyd_insert_sibling(lyd_child_no_keys(dst), lyd_child_no_keys(src), NULL), LY_SUCCESS);
+ first = lyd_child_no_keys(src);
assert_true(first && first->meta && get_rbt(first->meta) && first->next);
assert_string_equal(first->meta->name, META_NAME);
- first = lyd_child(dst);
+ first = lyd_child_no_keys(dst);
assert_true(first && !first->meta && first->next);
assert_string_equal(lyd_get_value(first), "1");
lyd_free_all(src);
@@ -1432,11 +1428,11 @@ test_move_part_list(void **state)
assert_int_equal(lyd_new_term(src, mod, "ll", "3", 0, &node), LY_SUCCESS);
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &dst), LY_SUCCESS);
assert_int_equal(lyd_new_term(dst, mod, "head", "a", 0, &node), LY_SUCCESS);
- assert_int_equal(lyd_insert_sibling(lyd_child(dst), lyd_child(src), NULL), LY_SUCCESS);
- first = lyd_child(src);
+ assert_int_equal(lyd_insert_sibling(lyd_child_no_keys(dst), lyd_child_no_keys(src), NULL), LY_SUCCESS);
+ first = lyd_child_no_keys(src);
assert_true(first && first->meta && get_rbt(first->meta) && first->next);
assert_string_equal(first->meta->name, META_NAME);
- first = lyd_child(dst);
+ first = lyd_child_no_keys(dst);
assert_true(first && first->next);
node = first->next;
assert_true(node && !node->meta && !node->next);
@@ -1552,9 +1548,9 @@ test_unlink_siblings(void **state)
assert_int_equal(lyd_new_term(cont, mod, "tail", "a", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "tail", "b", 0, NULL), LY_SUCCESS);
- node = lyd_child(cont)->next;
+ node = lyd_child_no_keys(cont)->next;
assert_int_equal(lyd_unlink_siblings(node), LY_SUCCESS);
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
assert_true(first && first->meta && !first->next);
assert_string_equal(first->meta->name, META_NAME);
assert_string_equal(lyd_get_value(first), "1");
@@ -1568,9 +1564,9 @@ test_unlink_siblings(void **state)
/* call lyds_split but no metadata is set */
data = "{\"a:cn\": {\"ll\":[1,2,3,4]} }";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_ORDERED, LYD_VALIDATE_PRESENT, LY_SUCCESS, cont);
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
assert_true(!first->meta);
- node = lyd_child(cont)->next;
+ node = lyd_child_no_keys(cont)->next;
lyd_unlink_siblings(node);
assert_true(node && !node->meta && node->next);
assert_string_equal(lyd_get_value(node), "2");
@@ -1583,9 +1579,9 @@ test_unlink_siblings(void **state)
assert_int_equal(lyd_new_inner(NULL, mod, "cn", 0, &cont), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "1", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_term(cont, mod, "ll", "2", 0, NULL), LY_SUCCESS);
- first = lyd_child(cont);
+ first = lyd_child_no_keys(cont);
assert_true(first->meta);
- node = lyd_child(cont)->next;
+ node = lyd_child_no_keys(cont)->next;
lyd_unlink_siblings(node);
assert_true(node && !node->meta);
assert_string_equal(lyd_get_value(node), "2");
@@ -1679,7 +1675,6 @@ main(void)
UTEST(test_parse_ordered_data),
UTEST(test_print_data),
UTEST(test_manipulation_of_many_nodes),
- UTEST(test_lyds_free_metadata),
UTEST(test_move_whole_list),
UTEST(test_move_part_list),
UTEST(test_merge_whole_list),
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
index 7ecaeb5a48..999d0685a5 100644
--- a/tests/utests/data/test_validation.c
+++ b/tests/utests/data/test_validation.c
@@ -22,8 +22,6 @@
#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) \
@@ -65,8 +63,8 @@ test_when(void **state)
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(lyd_child_no_keys(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_no_keys(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);
@@ -153,8 +151,8 @@ test_mandatory_when(void **state)
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);
+ CHECK_LYSC_NODE(lyd_child_no_keys(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_no_keys(tree)->next->flags);
lyd_free_all(tree);
}
@@ -1874,6 +1872,66 @@ test_when_must_cross_ref(void **state)
CHECK_LOG_CTX("When condition \"../flag = 'true'\" not satisfied.", "/twm5:top/outer", 0);
}
+static void
+test_when_nested(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module poc {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:poc\";\n"
+ " prefix p;\n"
+ "\n"
+ " container config {\n"
+ " presence \"config presence\";\n"
+ "\n"
+ " leaf enabled {\n"
+ " type boolean;\n"
+ " default true;\n"
+ " }\n"
+ "\n"
+ " container ref-container {\n"
+ " when \"../enabled = 'true'\";\n"
+ "\n"
+ " leaf ref-val {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " container data {\n"
+ " when \"../enabled = 'true'\";\n"
+ "\n"
+ " leaf name {\n"
+ " type string;\n"
+ " default \"default-name\";\n"
+ " }\n"
+ "\n"
+ " container child {\n"
+ " when \"../../ref-container/ref-val = 'target'\";\n"
+ "\n"
+ " leaf value {\n"
+ " type string;\n"
+ " default \"default-value\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ const char *data =
+ "\n"
+ " false\n"
+ " \n"
+ " target\n"
+ " \n"
+ "\n";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0,
+ LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree);
+ CHECK_LOG_CTX("When condition \"../enabled = 'true'\" not satisfied.", "/poc:config/ref-container", 0);
+}
+
int
main(void)
{
@@ -1899,6 +1957,7 @@ main(void)
UTEST(test_case),
UTEST(test_pattern),
UTEST(test_store_only),
+ UTEST(test_when_nested),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/utests/extensions/test_metadata.c b/tests/utests/extensions/test_metadata.c
index d81a1acd61..e011b80dc2 100644
--- a/tests/utests/extensions/test_metadata.c
+++ b/tests/utests/extensions/test_metadata.c
@@ -15,8 +15,6 @@
#include "utests.h"
#include "libyang.h"
-#include "plugins_exts.h"
-#include "plugins_exts/metadata.h"
static void
test_yang(void **state)
diff --git a/tests/utests/extensions/test_schema_mount.c b/tests/utests/extensions/test_schema_mount.c
index 077137dc5a..58abac71f4 100644
--- a/tests/utests/extensions/test_schema_mount.c
+++ b/tests/utests/extensions/test_schema_mount.c
@@ -234,7 +234,7 @@ test_parse_invalid(void **state)
ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, NULL);
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
assert_string_equal(LYD_NAME(data), "root");
- assert_null(lyd_child(data));
+ assert_null(lyd_child_no_keys(data));
assert_non_null(data->next);
assert_true(data->next->flags & LYD_DEFAULT);
lyd_free_siblings(data);
@@ -244,7 +244,7 @@ test_parse_invalid(void **state)
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
assert_string_equal(LYD_NAME(data), "root");
- assert_null(lyd_child(data));
+ assert_null(lyd_child_no_keys(data));
assert_non_null(data->next);
assert_true(data->next->flags & LYD_DEFAULT);
lyd_free_siblings(data);
@@ -472,6 +472,7 @@ test_parse_inline(void **state)
{
const char *xml, *json;
char *lyb;
+ uint32_t lyb_len;
struct lyd_node *data;
const struct ly_ctx *ext_ctx;
@@ -557,7 +558,7 @@ test_parse_inline(void **state)
"\n";
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_SIBLINGS);
- ext_ctx = LYD_CTX(lyd_child(data));
+ ext_ctx = LYD_CTX(lyd_child_no_keys(data));
lyd_free_siblings(data);
json =
@@ -587,7 +588,7 @@ test_parse_inline(void **state)
"}\n";
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_SIBLINGS);
- assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+ assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child_no_keys(data)));
lyd_free_siblings(data);
/* different yang-lib data with the same content-id */
@@ -658,19 +659,19 @@ test_parse_inline(void **state)
"");
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_SIBLINGS);
- assert_ptr_not_equal(ext_ctx, LYD_CTX(lyd_child(data)));
- ext_ctx = LYD_CTX(lyd_child(data));
+ assert_ptr_not_equal(ext_ctx, LYD_CTX(lyd_child_no_keys(data)));
+ ext_ctx = LYD_CTX(lyd_child_no_keys(data));
lyd_free_siblings(data);
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_SIBLINGS);
- assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+ assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child_no_keys(data)));
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&lyb, data, LYD_LYB, 0));
+ assert_int_equal(LY_SUCCESS, utest_lyd_print_mem_len(&lyb, &lyb_len, data, LYD_LYB, 0));
lyd_free_siblings(data);
- CHECK_PARSE_LYD_PARAM(lyb, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
- assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child(data)));
+ CHECK_PARSE_LYD_PARAM_LEN(lyb, lyb_len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ assert_ptr_equal(ext_ctx, LYD_CTX(lyd_child_no_keys(data)));
free(lyb);
lyd_free_siblings(data);
}
@@ -680,6 +681,7 @@ test_parse_shared(void **state)
{
const char *xml, *json;
char *lyb;
+ uint32_t lyb_len;
struct lyd_node *data;
ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
@@ -1089,10 +1091,11 @@ test_parse_shared(void **state)
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, json, LYD_JSON, LYD_PRINT_SIBLINGS);
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&lyb, data, LYD_LYB, LYD_PRINT_SIBLINGS));
+ assert_int_equal(LY_SUCCESS,
+ utest_lyd_print_mem_len(&lyb, &lyb_len, data, LYD_LYB, LYD_PRINT_SIBLINGS));
lyd_free_siblings(data);
- CHECK_PARSE_LYD_PARAM(lyb, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_PARSE_LYD_PARAM_LEN(lyb, lyb_len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
free(lyb);
lyd_free_siblings(data);
}
@@ -1420,7 +1423,8 @@ test_parse_config(void **state)
{
const char *xml;
char *lyb;
- struct lyd_node *data;
+ uint32_t lyb_len;
+ struct lyd_node *data, *key_node;
const struct lyd_node *node;
ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
@@ -1497,34 +1501,33 @@ test_parse_config(void **state)
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_SIBLINGS);
- node = lyd_child(data);
+ node = lyd_child_no_keys(data);
assert_string_equal(LYD_NAME(node), "interfaces");
assert_true(node->schema->flags & LYS_CONFIG_R);
- node = lyd_child(node);
+ node = lyd_child_no_keys(node);
assert_string_equal(LYD_NAME(node), "interface");
assert_true(node->schema->flags & LYS_CONFIG_R);
- node = lyd_child(node);
- assert_string_equal(LYD_NAME(node), "name");
- assert_true(node->schema->flags & LYS_CONFIG_R);
- node = node->next;
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node, "name", 0, &key_node));
+ assert_string_equal(LYD_NAME(key_node), "name");
+ assert_true(key_node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child_no_keys(node);
assert_string_equal(LYD_NAME(node), "type");
assert_true(node->schema->flags & LYS_CONFIG_R);
-
- lyd_print_mem(&lyb, data, LYD_LYB, 0);
+ assert_int_equal(LY_SUCCESS, utest_lyd_print_mem_len(&lyb, &lyb_len, data, LYD_LYB, 0));
lyd_free_siblings(data);
- CHECK_PARSE_LYD_PARAM(lyb, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_PARSE_LYD_PARAM_LEN(lyb, lyb_len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
free(lyb);
- node = lyd_child(data);
+ node = lyd_child_no_keys(data);
assert_string_equal(LYD_NAME(node), "interfaces");
assert_true(node->schema->flags & LYS_CONFIG_R);
- node = lyd_child(node);
+ node = lyd_child_no_keys(node);
assert_string_equal(LYD_NAME(node), "interface");
assert_true(node->schema->flags & LYS_CONFIG_R);
- node = lyd_child(node);
- assert_string_equal(LYD_NAME(node), "name");
- assert_true(node->schema->flags & LYS_CONFIG_R);
- node = node->next;
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node, "name", 0, &key_node));
+ assert_string_equal(LYD_NAME(key_node), "name");
+ assert_true(key_node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child_no_keys(node);
assert_string_equal(LYD_NAME(node), "type");
assert_true(node->schema->flags & LYS_CONFIG_R);
@@ -1604,16 +1607,16 @@ test_parse_config(void **state)
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_SIBLINGS);
- node = lyd_child(data->next->next->next);
+ node = lyd_child_no_keys(data->next->next->next);
assert_string_equal(LYD_NAME(node), "interfaces");
assert_true(node->schema->flags & LYS_CONFIG_R);
- node = lyd_child(node);
+ node = lyd_child_no_keys(node);
assert_string_equal(LYD_NAME(node), "interface");
assert_true(node->schema->flags & LYS_CONFIG_R);
- node = lyd_child(node);
- assert_string_equal(LYD_NAME(node), "name");
- assert_true(node->schema->flags & LYS_CONFIG_R);
- node = node->next;
+ assert_int_equal(LY_SUCCESS, lyd_find_path(node, "name", 0, &key_node));
+ assert_string_equal(LYD_NAME(key_node), "name");
+ assert_true(key_node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child_no_keys(node);
assert_string_equal(LYD_NAME(node), "type");
assert_true(node->schema->flags & LYS_CONFIG_R);
diff --git a/tests/utests/extensions/test_structure.c b/tests/utests/extensions/test_structure.c
index d8bea8ea99..8e9fdf812b 100644
--- a/tests/utests/extensions/test_structure.c
+++ b/tests/utests/extensions/test_structure.c
@@ -212,6 +212,7 @@ test_parse(void **state)
struct lyd_node *tree = NULL, *node;
const char *yang, *xml, *json;
char *lyb;
+ uint32_t lyb_len;
yang = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
"import ietf-yang-structure-ext {prefix sx;}"
@@ -249,10 +250,11 @@ test_parse(void **state)
ly_out_new_memory(&lyb, 0, &UTEST_OUT);
assert_int_equal(LY_SUCCESS, lyd_print_tree(UTEST_OUT, tree, LYD_LYB, 0));
+ lyb_len = (uint32_t)ly_out_printed(UTEST_OUT);
ly_out_free(current_utest_context->out, NULL, 0);
lyd_free_all(tree);
- ly_in_memory(UTEST_IN, lyb);
- assert_int_equal(LY_SUCCESS, lyd_parse_data(UTEST_LYCTX, NULL, UTEST_IN, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, lyb, lyb_len, LYD_LYB, LYD_PARSE_STRICT,
+ LYD_VALIDATE_PRESENT, &tree));
free(lyb);
lyd_free_all(tree);
@@ -281,14 +283,15 @@ test_parse(void **state)
ly_out_new_memory(&lyb, 0, &UTEST_OUT);
assert_int_equal(LY_SUCCESS, lyd_print_tree(UTEST_OUT, tree, LYD_LYB, 0));
+ lyb_len = (uint32_t)ly_out_printed(UTEST_OUT);
ly_out_free(current_utest_context->out, NULL, 0);
lyd_free_all(tree);
- ly_in_memory(UTEST_IN, lyb);
- assert_int_equal(LY_SUCCESS, lyd_parse_data(UTEST_LYCTX, NULL, UTEST_IN, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, lyb, lyb_len, LYD_LYB, LYD_PARSE_STRICT,
+ LYD_VALIDATE_PRESENT, &tree));
free(lyb);
/* invalid data */
- node = lyd_child(lyd_child(lyd_child(lyd_child(tree))));
+ node = lyd_child_no_keys(lyd_child_no_keys(lyd_child_no_keys(lyd_child_no_keys(tree))));
assert_string_equal(LYD_NAME(node->next), "y");
lyd_free_tree(node->next);
assert_string_equal(LYD_NAME(node), "x");
diff --git a/tests/utests/node/list.c b/tests/utests/node/list.c
index 5d2d3f4717..c727178817 100644
--- a/tests/utests/node/list.c
+++ b/tests/utests/node/list.c
@@ -21,7 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
#define LYD_TREE_CREATE(INPUT, MODEL) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL)
diff --git a/tests/utests/restriction/test_pattern.c b/tests/utests/restriction/test_pattern.c
index 56c1499408..b94a3f3f34 100644
--- a/tests/utests/restriction/test_pattern.c
+++ b/tests/utests/restriction/test_pattern.c
@@ -21,7 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"\n" \
diff --git a/tests/utests/restriction/test_range.c b/tests/utests/restriction/test_range.c
index 13cccfa476..ab15876bb9 100644
--- a/tests/utests/restriction/test_range.c
+++ b/tests/utests/restriction/test_range.c
@@ -21,7 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"\n" \
diff --git a/tests/utests/schema/test_printer_sid.c b/tests/utests/schema/test_printer_sid.c
new file mode 100644
index 0000000000..729991b27b
--- /dev/null
+++ b/tests/utests/schema/test_printer_sid.c
@@ -0,0 +1,540 @@
+/**
+ * @file test_printer_sid.c
+ * @author: Petr Hanzlik
+ * @brief unit tests for functions from printer_sid.c
+ *
+ * Copyright (c) 2026 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 "tree_data.h"
+#include "tree_schema.h"
+
+/* 3 SID items: module/a01, /a01:cont, /a01:cont/l */
+static const char *mod_v1 =
+ "module a01 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:a01\";\n"
+ " prefix a01;\n"
+ " revision 2024-01-01;\n"
+ " container cont {\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+/* 5 SID items: v1 plus /a01:cont/l2 and /a01:cont/l3 */
+static const char *mod_v2 =
+ "module a01 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:a01\";\n"
+ " prefix a01;\n"
+ " revision 2024-02-02;\n"
+ " container cont {\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l2 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l3 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+/* 4 SID items: compared to v1 drops /a01:cont/l and adds /a01:cont/m and /a01:cont/n */
+static const char *mod_v3 =
+ "module a01 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:a01\";\n"
+ " prefix a01;\n"
+ " revision 2024-03-03;\n"
+ " container cont {\n"
+ " leaf m {\n"
+ " type string;\n"
+ " }\n"
+ " leaf n {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+/* 7 SID items: compared to v3 keeps only /a01:cont and adds 5 new leaves;
+ the dropped items /a01:cont/l, /a01:cont/m and /a01:cont/n become obsolete
+ and keep holding SIDs 102, 200 and 300 */
+static const char *mod_v4 =
+ "module a01 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:a01\";\n"
+ " prefix a01;\n"
+ " revision 2024-04-04;\n"
+ " container cont {\n"
+ " leaf p1 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf p2 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf p3 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf p4 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf p5 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+/**
+ * @brief Compare the compact JSON print of a data tree with an expected string.
+ */
+static void
+check_json_tree(const struct lyd_node *tree, const char *expected)
+{
+ char *buffer = NULL;
+
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, (struct lyd_node *)tree, LYD_JSON, LYD_PRINT_SHRINK));
+ CHECK_STRING(buffer, expected);
+ free(buffer);
+}
+
+/**
+ * @brief Create a context with the given module implemented and ietf-sid-file loaded.
+ */
+static void
+new_sid_ctx(struct ly_ctx **ctx, const char *mod_str, struct lys_module **mod)
+{
+ struct ly_in *in;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_SRC "/../modules", LY_CTX_DISABLE_SEARCHDIR_CWD, ctx));
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(mod_str, &in));
+ assert_int_equal(LY_SUCCESS, lys_parse(*ctx, in, LYS_IN_YANG, NULL, mod));
+ ly_in_free(in, 0);
+ assert_non_null(ly_ctx_load_module(*ctx, "ietf-sid-file", NULL, NULL));
+}
+
+/**
+ * @brief Check and clear the last error logged in @p ctx (CHECK_LOG_CTX for private contexts).
+ */
+static void
+check_log_ctx(struct ly_ctx *ctx, const char *msg)
+{
+ struct ly_err_item *e = (struct ly_err_item *)ly_err_last(ctx);
+
+ assert_non_null(e);
+ CHECK_STRING(e->msg, msg);
+ assert_null(e->data_path);
+ assert_null(e->schema_path);
+ assert_int_equal(e->line, 0);
+ ly_err_clean(ctx, e);
+}
+
+/**
+ * @brief Test case: argument checks of the public API functions lys_sid_gen(),
+ * lys_sid_update() and lys_sid_range_add(). These fail in the API wrapper without
+ * logging any error into the context.
+ */
+static void
+test_args(void **state)
+{
+ struct lys_module *mod;
+ struct lyd_node *sid_file = NULL, *updated = NULL;
+
+ UTEST_ADD_MODULE(mod_v1, LYS_IN_YANG, NULL, &mod);
+
+ /* lys_sid_gen */
+ assert_int_equal(LY_EINVAL, lys_sid_gen(NULL, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_int_equal(LY_EINVAL, lys_sid_gen(mod, 100, 0, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_int_equal(LY_EINVAL, lys_sid_gen(mod, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", NULL));
+
+ /* the ietf-sid-file module is not implemented in the context yet */
+ assert_int_equal(LY_ENOTFOUND, lys_sid_gen(mod, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(ly_ctx_load_module(_UC->ctx, "ietf-sid-file", NULL, NULL));
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(mod, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(sid_file);
+
+ /* lys_sid_update */
+ assert_int_equal(LY_EINVAL, lys_sid_update(NULL, sid_file, LYS_SID_FILE_UNPUBLISHED, "d", &updated));
+ assert_int_equal(LY_EINVAL, lys_sid_update(mod, NULL, LYS_SID_FILE_UNPUBLISHED, "d", &updated));
+ assert_int_equal(LY_EINVAL, lys_sid_update(mod, sid_file, LYS_SID_FILE_UNPUBLISHED, "d", NULL));
+
+ /* lys_sid_range_add */
+ assert_int_equal(LY_EINVAL, lys_sid_range_add(NULL, 200, 1));
+ assert_int_equal(LY_EINVAL, lys_sid_range_add(sid_file, 200, 0));
+
+ lyd_free_all(sid_file);
+}
+
+/**
+ * @brief Test case: lys_sid_gen() fails on an undersized assignment range
+ * and generates the expected data tree with a sufficient one.
+ */
+static void
+test_gen(void **state)
+{
+ struct lys_module *mod;
+ struct lyd_node *sid_file = NULL;
+
+ UTEST_ADD_MODULE(mod_v1, LYS_IN_YANG, NULL, &mod);
+ assert_non_null(ly_ctx_load_module(_UC->ctx, "ietf-sid-file", NULL, NULL));
+
+ /* the module has 3 SID items but the range covers only 2 */
+ assert_int_equal(LY_EINVAL, lys_sid_gen(mod, 100, 2, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_null(sid_file);
+ CHECK_LOG_CTX(".sid assignment range(s) size 2 is too small, 1 extra SID(s) are required.", NULL, 0);
+
+ /* exact range size */
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(mod, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(sid_file);
+ check_json_tree(sid_file,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"a01\","
+ "\"module-revision\":\"2024-01-01\","
+ "\"sid-file-status\":\"unpublished\","
+ "\"description\":\"d\","
+ "\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"3\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"a01\",\"status\":\"unstable\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont\",\"status\":\"unstable\",\"sid\":\"101\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/l\",\"status\":\"unstable\",\"sid\":\"102\"}"
+ "]}}");
+
+ lyd_free_all(sid_file);
+}
+
+/**
+ * @brief Test case: chained update scenario on a .sid file: undersized
+ * updates fail, assignment ranges are added (zero-size and overlapping rejected),
+ * an update with removed/added items succeeds and is finally republished as stable.
+ * A last update fails on range exhaustion: obsolete items keep holding their SIDs,
+ * so no free SID is left in any range even though the raw item count fits.
+ */
+static void
+test_flow(void **state)
+{
+ struct lys_module *mod, *mod2, *mod3, *mod4;
+ struct ly_ctx *ctx2 = NULL, *ctx3 = NULL, *ctx4 = NULL;
+ struct lyd_node *prev = NULL, *updated = NULL, *published = NULL;
+ struct lyd_node *node;
+ char *json = NULL;
+
+ /* --- stage with v1 ---
+ generate the initial .sid file with the range [100, 102] */
+ UTEST_ADD_MODULE(mod_v1, LYS_IN_YANG, NULL, &mod);
+ assert_non_null(ly_ctx_load_module(_UC->ctx, "ietf-sid-file", NULL, NULL));
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(mod, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &prev));
+ assert_non_null(prev);
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, prev, LYD_JSON, LYD_PRINT_SHRINK));
+ lyd_free_all(prev);
+ prev = NULL;
+
+ /* --- stage with v2 --- */
+ new_sid_ctx(&ctx2, mod_v2, &mod2);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx2, json, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &prev));
+ free(json);
+ json = NULL;
+
+ /* v2 has 5 items but the ranges cover only 3 */
+ assert_int_equal(LY_EINVAL, lys_sid_update(mod2, prev, LYS_SID_FILE_UNPUBLISHED, "d", &updated));
+ assert_null(updated);
+ check_log_ctx(ctx2, ".sid assignment range(s) size 3 is too small, 2 extra SID(s) are required.");
+
+ /* overlapping range rejected */
+ assert_int_equal(LY_EINVAL, lys_sid_range_add(prev, 102, 5));
+ check_log_ctx(ctx2, "The assignment range [102, 106] overlaps the existing assignment range [100, 102].");
+
+ /* valid but still insufficient range is appended */
+ assert_int_equal(LY_SUCCESS, lys_sid_range_add(prev, 200, 1));
+ assert_int_equal(LY_SUCCESS,
+ lyd_find_path(prev, "/ietf-sid-file:sid-file/assignment-range[entry-point='100']/size", 0, &node));
+ CHECK_STRING(lyd_get_value(node), "3");
+ assert_int_equal(LY_SUCCESS,
+ lyd_find_path(prev, "/ietf-sid-file:sid-file/assignment-range[entry-point='200']/size", 0, &node));
+ CHECK_STRING(lyd_get_value(node), "1");
+
+ /* total capacity 4 still does not cover the 5 items of v2 */
+ assert_int_equal(LY_EINVAL, lys_sid_update(mod2, prev, LYS_SID_FILE_UNPUBLISHED, "d", &updated));
+ assert_null(updated);
+ check_log_ctx(ctx2, ".sid assignment range(s) size 4 is too small, 1 extra SID(s) are required.");
+
+ /* another range provides enough SIDs */
+ assert_int_equal(LY_SUCCESS, lys_sid_range_add(prev, 300, 5));
+
+ /* carry the .sid file over to the next stage */
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, prev, LYD_JSON, LYD_PRINT_SHRINK));
+ lyd_free_all(prev);
+ prev = NULL;
+ ly_ctx_destroy(ctx2);
+ ctx2 = NULL;
+
+ /* --- stage with v3 --- */
+ new_sid_ctx(&ctx3, mod_v3, &mod3);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx3, json, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &prev));
+ free(json);
+ json = NULL;
+
+ /* update to v3 - drops /a01:cont/l (kept as obsolete), adds /a01:cont/m and /a01:cont/n
+ which get the next free SIDs walking the ranges forward (200, then 300) */
+ assert_int_equal(LY_SUCCESS, lys_sid_update(mod3, prev, LYS_SID_FILE_UNPUBLISHED, "d", &updated));
+ assert_non_null(updated);
+ check_json_tree(updated,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"a01\","
+ "\"module-revision\":\"2024-03-03\","
+ "\"sid-file-version\":1,"
+ "\"sid-file-status\":\"unpublished\","
+ "\"description\":\"d\","
+ "\"assignment-range\":["
+ "{\"entry-point\":\"100\",\"size\":\"3\"},"
+ "{\"entry-point\":\"200\",\"size\":\"1\"},"
+ "{\"entry-point\":\"300\",\"size\":\"5\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"a01\",\"status\":\"unstable\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont\",\"status\":\"unstable\",\"sid\":\"101\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/l\",\"status\":\"obsolete\",\"sid\":\"102\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/m\",\"status\":\"unstable\",\"sid\":\"200\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/n\",\"status\":\"unstable\",\"sid\":\"300\"}"
+ "]}}");
+ lyd_free_all(prev);
+ prev = NULL;
+
+ /* republish the file as stable - the version is incremented, the sid-file-status leaf
+ and unstable item statuses disappear, the obsolete item is preserved */
+ assert_int_equal(LY_SUCCESS, lys_sid_update(mod3, updated, LYS_SID_FILE_PUBLISHED, "d", &published));
+ assert_non_null(published);
+ check_json_tree(published,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"a01\","
+ "\"module-revision\":\"2024-03-03\","
+ "\"sid-file-version\":2,"
+ "\"description\":\"d\","
+ "\"assignment-range\":["
+ "{\"entry-point\":\"100\",\"size\":\"3\"},"
+ "{\"entry-point\":\"200\",\"size\":\"1\"},"
+ "{\"entry-point\":\"300\",\"size\":\"5\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"a01\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont\",\"sid\":\"101\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/l\",\"status\":\"obsolete\",\"sid\":\"102\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/m\",\"sid\":\"200\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/a01:cont/n\",\"sid\":\"300\"}"
+ "]}}");
+ lyd_free_all(updated);
+ updated = NULL;
+
+ /* --- stage with v4 --- */
+ /* v4 has 7 items, so the raw size check (capacity 9) passes, but the obsolete
+ items l/m/n still lock SIDs 102/200/300 and only 301-304 are free - the 5th
+ new leaf finds no free SID in any assignment range */
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, published, LYD_JSON, LYD_PRINT_SHRINK));
+ lyd_free_all(published);
+ ly_ctx_destroy(ctx3);
+
+ new_sid_ctx(&ctx4, mod_v4, &mod4);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx4, json, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &prev));
+ free(json);
+ json = NULL;
+
+ assert_int_equal(LY_EINVAL, lys_sid_update(mod4, prev, LYS_SID_FILE_UNPUBLISHED, "d", &updated));
+ assert_null(updated);
+ check_log_ctx(ctx4, ".sid assignment range(s) size 9 is too small, 1 extra SID(s) are required.");
+
+ lyd_free_all(prev);
+ ly_ctx_destroy(ctx4);
+}
+
+/**
+ * @brief Test case: SID items are also collected from the data trees of extension
+ * instances that define their own data trees outside the standard module trees -
+ * sx:structure (with the contents of the merged sx:augment-structure; the structure
+ * root itself, the synthetic top container named by the extension argument, gets no
+ * SID and only prefixes the descendant identifiers) and rc:yang-data (the template
+ * container is the data tree root, so the extension argument is not among the items).
+ */
+static void
+test_exts(void **state)
+{
+ struct lys_module *mod;
+ struct lyd_node *sid_file = NULL;
+ static const char *mod_struct =
+ "module s1 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:s1\";\n"
+ " prefix s1;\n"
+ " import ietf-yang-structure-ext { prefix sx; }\n"
+ " revision 2024-01-01;\n"
+ " container c {\n"
+ " leaf l { type string; }\n"
+ " }\n"
+ " sx:structure struct {\n"
+ " container x {\n"
+ " list l {\n"
+ " key \"id\";\n"
+ " leaf id { type uint32; }\n"
+ " leaf v { type string; }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " sx:augment-structure \"/s1:struct/x\" {\n"
+ " leaf al { type string; }\n"
+ " }\n"
+ "}\n";
+ static const char *mod_yangdata =
+ "module yd1 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:yd1\";\n"
+ " prefix yd1;\n"
+ " import ietf-restconf { revision-date 2017-01-26; prefix rc; }\n"
+ " revision 2024-01-01;\n"
+ " rc:yang-data template {\n"
+ " container y {\n"
+ " leaf l { type string; }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ /* sx:structure: 8 SID items, the root "struct" itself is not included (the structure
+ storage points below the synthetic top container), augments merged in */
+ UTEST_ADD_MODULE(mod_struct, LYS_IN_YANG, NULL, &mod);
+ assert_non_null(ly_ctx_load_module(_UC->ctx, "ietf-sid-file", NULL, NULL));
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(mod, 100, 8, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(sid_file);
+ check_json_tree(sid_file,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"s1\","
+ "\"module-revision\":\"2024-01-01\","
+ "\"sid-file-status\":\"unpublished\","
+ "\"description\":\"d\","
+ "\"dependency-revision\":[{\"module-name\":\"ietf-yang-structure-ext\",\"module-revision\":\"2020-06-17\"}],"
+ "\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"8\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"s1\",\"status\":\"unstable\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:c\",\"status\":\"unstable\",\"sid\":\"101\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:c/l\",\"status\":\"unstable\",\"sid\":\"102\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:struct/x\",\"status\":\"unstable\",\"sid\":\"103\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:struct/x/al\",\"status\":\"unstable\",\"sid\":\"104\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:struct/x/l\",\"status\":\"unstable\",\"sid\":\"105\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:struct/x/l/id\",\"status\":\"unstable\",\"sid\":\"106\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/s1:struct/x/l/v\",\"status\":\"unstable\",\"sid\":\"107\"}"
+ "]}}");
+ lyd_free_all(sid_file);
+ sid_file = NULL;
+
+ /* rc:yang-data: 3 SID items, the "template" name is not among them */
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(_UC->ctx, TESTS_DIR_MODULES_YANG));
+ UTEST_ADD_MODULE(mod_yangdata, LYS_IN_YANG, NULL, &mod);
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(mod, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(sid_file);
+ check_json_tree(sid_file,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"yd1\","
+ "\"module-revision\":\"2024-01-01\","
+ "\"sid-file-status\":\"unpublished\","
+ "\"description\":\"d\","
+ "\"dependency-revision\":[{\"module-name\":\"ietf-restconf\",\"module-revision\":\"2017-01-26\"}],"
+ "\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"3\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"yd1\",\"status\":\"unstable\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/yd1:y\",\"status\":\"unstable\",\"sid\":\"101\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/yd1:y/l\",\"status\":\"unstable\",\"sid\":\"102\"}"
+ "]}}");
+ lyd_free_all(sid_file);
+}
+
+/**
+ * @brief Test case: augment coverage. A module's .sid file must include the data
+ * nodes it augments into another module (RFC 9595), and a module's own .sid must
+ * not include nodes augmented into it by other modules.
+ */
+static void
+test_augment(void **state)
+{
+ struct lys_module *base, *aug;
+ struct lyd_node *sid_file = NULL;
+ static const char *mod_base =
+ "module b1 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:b1\";\n"
+ " prefix b1;\n"
+ " revision 2024-01-01;\n"
+ " container cont {\n"
+ " leaf l { type string; }\n"
+ " }\n"
+ "}\n";
+ static const char *mod_aug =
+ "module a1 {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:a1\";\n"
+ " prefix a1;\n"
+ " import b1 { prefix b1; }\n"
+ " revision 2024-01-01;\n"
+ " augment \"/b1:cont\" {\n"
+ " leaf x { type string; }\n"
+ " }\n"
+ "}\n";
+
+ UTEST_ADD_MODULE(mod_base, LYS_IN_YANG, NULL, &base);
+ UTEST_ADD_MODULE(mod_aug, LYS_IN_YANG, NULL, &aug);
+ assert_non_null(ly_ctx_load_module(_UC->ctx, "ietf-sid-file", NULL, NULL));
+
+ /* the augmenting module's .sid contains the node it augments in: /b1:cont/a1:x */
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(aug, 100, 2, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(sid_file);
+ check_json_tree(sid_file,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"a1\","
+ "\"module-revision\":\"2024-01-01\","
+ "\"sid-file-status\":\"unpublished\","
+ "\"description\":\"d\","
+ "\"dependency-revision\":[{\"module-name\":\"b1\",\"module-revision\":\"2024-01-01\"}],"
+ "\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"2\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"a1\",\"status\":\"unstable\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/b1:cont/a1:x\",\"status\":\"unstable\",\"sid\":\"101\"}"
+ "]}}");
+ lyd_free_all(sid_file);
+ sid_file = NULL;
+
+ /* the base module's own .sid must not contain the node augmented in by a1 */
+ assert_int_equal(LY_SUCCESS, lys_sid_gen(base, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
+ assert_non_null(sid_file);
+ check_json_tree(sid_file,
+ "{\"ietf-sid-file:sid-file\":{"
+ "\"module-name\":\"b1\","
+ "\"module-revision\":\"2024-01-01\","
+ "\"sid-file-status\":\"unpublished\","
+ "\"description\":\"d\","
+ "\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"3\"}],"
+ "\"item\":["
+ "{\"namespace\":\"module\",\"identifier\":\"b1\",\"status\":\"unstable\",\"sid\":\"100\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/b1:cont\",\"status\":\"unstable\",\"sid\":\"101\"},"
+ "{\"namespace\":\"data\",\"identifier\":\"/b1:cont/l\",\"status\":\"unstable\",\"sid\":\"102\"}"
+ "]}}");
+ lyd_free_all(sid_file);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_args),
+ UTEST(test_gen),
+ UTEST(test_flow),
+ UTEST(test_exts),
+ UTEST(test_augment),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/schema/test_printer_tree.c b/tests/utests/schema/test_printer_tree.c
index e143564337..13983a6231 100644
--- a/tests/utests/schema/test_printer_tree.c
+++ b/tests/utests/schema/test_printer_tree.c
@@ -15,7 +15,6 @@
#include "utests.h"
#include "context.h"
-#include "ly_common.h"
#include "out.h"
#include "printer_schema.h"
#include "tree_schema.h"
diff --git a/tests/utests/schema/test_schema.c b/tests/utests/schema/test_schema.c
index 3cf447f27c..cbe9829668 100644
--- a/tests/utests/schema/test_schema.c
+++ b/tests/utests/schema/test_schema.c
@@ -19,7 +19,6 @@
#include
#include
-#include "compat.h"
#include "context.h"
#include "log.h"
#include "parser_schema.h"
@@ -27,7 +26,6 @@
#include "set.h"
#include "tree_edit.h"
#include "tree_schema.h"
-#include "tree_schema_internal.h"
static LY_ERR
test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name),
@@ -246,28 +244,38 @@ test_getnext(void **state)
static void
test_date(void **state)
{
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, NULL, 0, "date"));
- CHECK_LOG_CTX("Invalid argument date (lys_check_date()).", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "x", 1, "date"));
- CHECK_LOG_CTX("Invalid length 1 of a date.", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "nonsencexx", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"nonsencexx\" of \"date\".", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "123x-11-11", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"123x-11-11\" of \"date\".", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "2018-13-11", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"2018-13-11\" of \"date\".", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "2018-11-41", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"2018-11-41\" of \"date\".", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "2018-02-29", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"2018-02-29\" of \"date\".", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "2018.02-28", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"2018.02-28\" of \"date\".", NULL, 0);
- assert_int_equal(LY_EINVAL, lys_check_date(UTEST_LYCTX, "2018-02.28", 10, "date"));
- CHECK_LOG_CTX("Invalid value \"2018-02.28\" of \"date\".", NULL, 0);
-
- assert_int_equal(LY_SUCCESS, lys_check_date(NULL, "2018-11-11", 10, "date"));
- assert_int_equal(LY_SUCCESS, lys_check_date(NULL, "2018-02-28", 10, "date"));
- assert_int_equal(LY_SUCCESS, lys_check_date(NULL, "2016-02-29", 10, "date"));
+ struct ly_ctx *ctx = UTEST_LYCTX;
+ char yang[256];
+ size_t i;
+ const char *invalid[] = {
+ "",
+ "x",
+ "nonsencexx",
+ "123x-11-11",
+ "2018-13-11",
+ "2018-11-41",
+ "2018-02-29",
+ "2018.02-28",
+ "2018-02.28"
+ };
+ const char *valid[] = {
+ "2018-11-11",
+ "2018-02-28",
+ "2016-02-29"
+ };
+
+ /* 1. Test Invalid Dates */
+ for (i = 0; i < sizeof(invalid) / sizeof(invalid[0]); ++i) {
+ snprintf(yang, sizeof(yang), "module a {namespace urn:a;prefix a;revision \"%s\";}", invalid[i]);
+ assert_int_equal(LY_EVALID, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
+ }
+
+ /* 2. Test Valid Dates */
+ for (i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) {
+ snprintf(yang, sizeof(yang), "module v%zu {namespace urn:v%zu;prefix v;revision \"%s\";}", i, i, valid[i]);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, yang, LYS_IN_YANG, NULL));
+ }
}
static void
@@ -1667,76 +1675,6 @@ test_extension_argument_element(void **state)
}
-static void
-test_extension_compile(void **state)
-{
- struct lys_module *mod;
- struct lysc_ctx cctx = {0};
- struct lysp_ext_instance ext_p = {0};
- struct lysp_ext_substmt *substmtp;
- struct lysp_stmt child = {0};
- struct lysc_ext_instance ext_c = {0};
- struct lysc_ext_substmt *substmt;
- LY_ERR rc = LY_SUCCESS;
-
- /* current module, whatever */
- mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "yang");
- assert_true(mod);
-
- /* compile context */
- cctx.ctx = UTEST_LYCTX;
- cctx.cur_mod = mod;
- cctx.pmod = mod->parsed;
- cctx.path_len = 1;
- cctx.path[0] = '/';
-
- /* parsed ext instance */
- lysdict_insert(UTEST_LYCTX, "pref:my-ext", 0, &ext_p.name);
- ext_p.format = LY_VALUE_JSON;
- ext_p.parent_stmt = LY_STMT_MODULE;
-
- LY_ARRAY_NEW_GOTO(UTEST_LYCTX, ext_p.substmts, substmtp, rc, cleanup);
-
- substmtp->stmt = LY_STMT_ERROR_MESSAGE;
- substmtp->storage_p = &ext_p.parsed;
- /* fake parse */
- lysdict_insert(UTEST_LYCTX, "my error", 0, (const char **)&ext_p.parsed);
-
- /* compiled ext instance */
- ext_c.parent_stmt = ext_p.parent_stmt;
- LY_ARRAY_NEW_GOTO(UTEST_LYCTX, ext_c.substmts, substmt, rc, cleanup);
-
- substmt->stmt = LY_STMT_ERROR_MESSAGE;
- substmt->storage_p = &ext_c.compiled;
-
- /*
- * error-message
- */
- ext_p.child = &child;
- lysdict_insert(UTEST_LYCTX, "error-message", 0, &child.stmt);
- lysdict_insert(UTEST_LYCTX, "my error", 0, &child.arg);
- child.format = LY_VALUE_JSON;
- child.kw = LY_STMT_ERROR_MESSAGE;
-
- /* compile */
- assert_int_equal(LY_SUCCESS, lyplg_ext_compile_extension_instance(&cctx, &ext_p, &ext_c, NULL));
-
- /* check */
- assert_string_equal(ext_c.compiled, "my error");
-
-cleanup:
- lysdict_remove(UTEST_LYCTX, ext_p.name);
- lysdict_remove(UTEST_LYCTX, child.stmt);
- lysdict_remove(UTEST_LYCTX, child.arg);
- LY_ARRAY_FREE(ext_p.substmts);
- lysdict_remove(UTEST_LYCTX, ext_p.parsed);
- LY_ARRAY_FREE(ext_c.substmts);
- lysdict_remove(UTEST_LYCTX, ext_c.compiled);
- if (rc) {
- fail();
- }
-}
-
static void
test_ext_recursive(void **state)
{
@@ -2313,7 +2251,6 @@ main(void)
UTEST(test_feature),
UTEST(test_extension_argument),
UTEST(test_extension_argument_element),
- UTEST(test_extension_compile),
UTEST(test_ext_recursive),
UTEST(test_lysc_path),
UTEST(test_lysc_backlinks),
diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c
index d2765d1fed..2b14282ffe 100644
--- a/tests/utests/schema/test_tree_schema_compile.c
+++ b/tests/utests/schema/test_tree_schema_compile.c
@@ -16,12 +16,7 @@
#include "utests.h"
#include "in.h"
-#include "ly_common.h"
-#include "parser_internal.h"
-#include "path.h"
#include "plugins_types.h"
-#include "schema_compile.h"
-#include "xpath.h"
static int
setup(void **state)
@@ -89,15 +84,13 @@ test_module(void **state)
struct lys_module *mod = NULL;
struct lysp_feature *f;
struct lysc_iffeature *iff;
- struct lys_glob_unres unres = {0};
str = "module test {namespace urn:test; prefix t;"
"feature f1;feature f2 {if-feature f1;}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod));
- lys_unres_glob_erase(&unres);
+ assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod));
ly_in_free(in, 0);
- assert_int_equal(0, mod->implemented);
+ assert_int_equal(1, mod->implemented);
assert_int_equal(LY_EINVAL, lys_set_implemented(mod, feats));
CHECK_LOG_CTX("Feature \"invalid\" not found in module \"test@\".", NULL, 0);
assert_int_equal(LY_SUCCESS, lys_set_implemented(mod, NULL));
@@ -120,8 +113,7 @@ test_module(void **state)
/* submodules cannot be compiled directly */
str = "submodule test {belongs-to xxx {prefix x;}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, NULL));
- lys_unres_glob_erase(&unres);
+ assert_int_equal(LY_EINVAL, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL));
ly_in_free(in, 0);
CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0);
@@ -1701,49 +1693,32 @@ test_type_leafref(void **state)
char *str;
struct lys_module *mod;
struct lysc_type *type;
- const char *path;
- struct lyxp_expr *expr;
-
- /* lys_path_parse() */
- path = "invalid_path";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- CHECK_LOG_CTX("Unexpected XPath token \"NameTest\" (\"invalid_path\"), expected \"..\".", NULL, 0);
-
- path = "..";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- CHECK_LOG_CTX("Unexpected XPath expression end.", NULL, 0);
-
- path = "..[";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- CHECK_LOG_CTX("Unexpected XPath token \"[\" (\"[\"), expected \"Operator(Path)\".", NULL, 0);
-
- path = "../";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- CHECK_LOG_CTX("Unexpected XPath expression end.", NULL, 0);
-
- path = "/";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- CHECK_LOG_CTX("Unexpected XPath expression end.", NULL, 0);
-
- path = "../../pref:id/xxx[predicate]/invalid!!!";
- assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- CHECK_LOG_CTX("Invalid character 0x21 ('!'), perhaps \"invalid\" is supposed to be a function call.", NULL, 0);
-
- path = "/absolute/prefix:path";
- assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr));
- assert_int_equal(4, expr->used);
- assert_int_equal(LYXP_TOKEN_OPER_PATH, expr->tokens[0]);
- assert_int_equal(LYXP_TOKEN_NAMETEST, expr->tokens[1]);
- assert_int_equal(LYXP_TOKEN_OPER_PATH, expr->tokens[2]);
- assert_int_equal(LYXP_TOKEN_NAMETEST, expr->tokens[3]);
- lyxp_expr_free(expr);
+ char yang[512];
+ size_t i;
+ const char *invalid[] = {
+ "invalid_path",
+ "..",
+ "..[",
+ "../",
+ "/",
+ "../../pref:id/xxx[predicate]/invalid!!!"
+ };
+
+ /* 1. Test Invalid Paths */
+ for (i = 0; i < sizeof(invalid) / sizeof(invalid[0]); ++i) {
+ snprintf(yang, sizeof(yang), "module a {namespace urn:a;prefix a; leaf l { type leafref { path \"%s\"; } } }", invalid[i]);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yang, LYS_IN_YANG, NULL));
+ UTEST_LOG_CTX_CLEAN;
+ }
+
+ /* 2. Test Valid Path */
+ const char *valid_yang =
+ "module v {namespace urn:v; prefix prefix;"
+ " container absolute { leaf path { type string; } }"
+ " leaf l { type leafref { path \"/absolute/prefix:path\"; } }"
+ "}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, valid_yang, LYS_IN_YANG, NULL));
/* complete leafref paths */
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module a {yang-version 1.1;namespace urn:a;prefix a;"
@@ -1752,15 +1727,14 @@ test_type_leafref(void **state)
type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
assert_non_null(type);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/a:target1", ((struct lysc_type_leafref *)type)->path->expr);
- assert_ptr_equal(mod, ly_resolve_prefix(UTEST_LYCTX, "a", 1, LY_VALUE_SCHEMA_RESOLVED, ((struct lysc_type_leafref *)type)->prefixes));
+ assert_string_equal("/a:target1", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_type_leafref *)type)->realtype->basetype);
assert_int_equal(1, ((struct lysc_type_leafref *)type)->require_instance);
type = ((struct lysc_node_leaf *)mod->compiled->data->next)->type;
assert_non_null(type);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/a/target2", ((struct lysc_type_leafref *)type)->path->expr);
+ assert_string_equal("/a/target2", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_type_leafref *)type)->prefixes));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_UINT8, ((struct lysc_type_leafref *)type)->realtype->basetype);
@@ -1773,8 +1747,7 @@ test_type_leafref(void **state)
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/b:target", ((struct lysc_type_leafref *)type)->path->expr);
- assert_ptr_equal(mod, ly_resolve_prefix(UTEST_LYCTX, "b", 1, LY_VALUE_SCHEMA_RESOLVED, ((struct lysc_type_leafref *)type)->prefixes));
+ assert_string_equal("/b:target", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_type_leafref *)type)->realtype->basetype);
assert_int_equal(1, ((struct lysc_type_leafref *)type)->require_instance);
@@ -1787,8 +1760,7 @@ test_type_leafref(void **state)
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/b:target", ((struct lysc_type_leafref *)type)->path->expr);
- assert_ptr_not_equal(mod, ly_resolve_prefix(UTEST_LYCTX, "b", 1, LY_VALUE_SCHEMA_RESOLVED, ((struct lysc_type_leafref *)type)->prefixes));
+ assert_string_equal("/b:target", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_type_leafref *)type)->realtype->basetype);
assert_int_equal(0, ((struct lysc_type_leafref *)type)->require_instance);
@@ -1796,8 +1768,7 @@ test_type_leafref(void **state)
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/b:target", ((struct lysc_type_leafref *)type)->path->expr);
- assert_ptr_not_equal(mod, ly_resolve_prefix(UTEST_LYCTX, "b", 1, LY_VALUE_SCHEMA_RESOLVED, ((struct lysc_type_leafref *)type)->prefixes));
+ assert_string_equal("/b:target", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_int_equal(1, ((struct lysc_type_leafref *)type)->require_instance);
/* non-prefixed nodes in path are supposed to be from the module where the leafref type is instantiated */
@@ -1807,7 +1778,7 @@ test_type_leafref(void **state)
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/target", ((struct lysc_type_leafref *)type)->path->expr);
+ assert_string_equal("/target", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_type_leafref *)type)->prefixes));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_INT8, ((struct lysc_type_leafref *)type)->realtype->basetype);
@@ -1847,12 +1818,12 @@ test_type_leafref(void **state)
"container default-address{leaf ifname{type leafref{ path \"../../interface/name\";}}"
"leaf address {type leafref{ path \"../../interface[ name = current()/../ifname ]/address/ip\";}}}}",
LYS_IN_YANG, &mod));
- type = ((struct lysc_node_leaf *)(*lysc_node_child_p(mod->compiled->data->prev))->prev)->type;
+ type = ((struct lysc_node_leaf *)(lysc_node_child(mod->compiled->data->prev)->prev))->type;
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
assert_string_equal("../../interface[ name = current()/../ifname ]/address/ip",
- ((struct lysc_type_leafref *)type)->path->expr);
+ lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_type_leafref *)type)->prefixes));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_type_leafref *)type)->realtype->basetype);
@@ -1865,7 +1836,7 @@ test_type_leafref(void **state)
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("/endpoint-parent[id=current()/../field]/endpoint/name", ((struct lysc_type_leafref *)type)->path->expr);
+ assert_string_equal("/endpoint-parent[id=current()/../field]/endpoint/name", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_type_leafref *)type)->prefixes));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_type_leafref *)type)->realtype->basetype);
@@ -1909,7 +1880,7 @@ test_type_leafref(void **state)
assert_non_null(type);
assert_int_equal(1, type->refcount);
assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
- assert_string_equal("../target", ((struct lysc_type_leafref *)type)->path->expr);
+ assert_string_equal("../target", lyxp_get_expr(((struct lysc_type_leafref *)type)->path));
assert_non_null(((struct lysc_type_leafref *)type)->realtype);
assert_int_equal(LY_TYPE_BOOL, ((struct lysc_type_leafref *)type)->realtype->basetype);
assert_non_null(((struct lysc_node_leaf *)mod->compiled->data)->dflt.str);
@@ -2982,10 +2953,10 @@ test_augment(void **state)
assert_non_null(node = ((struct lysc_node_container *)node)->child);
assert_string_equal("p", node->name);
assert_non_null(node = node->next);
+ assert_string_equal("ll", node->name);
+ assert_non_null(node = node->next);
assert_string_equal("l", node->name);
assert_true(node->flags & LYS_CONFIG_R);
- assert_non_null(node = node->next);
- assert_string_equal("ll", node->name);
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module i {namespace urn:i;prefix i;import himp {prefix hi;}"
"augment /hi:func/hi:input {leaf x {type string;}}"
@@ -3063,8 +3034,8 @@ test_augment(void **state)
assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh;import himp {prefix hi;}"
"augment /hi:func/input {leaf x {type string;}}"
"augment /hi:func/output {leaf y {type string;}}}", LYS_IN_YANG, NULL));
- CHECK_LOG_CTX("Augment target node \"/hi:func/input\" from module \"hh\" was not found.", "/hh:{augment='/hi:func/input'}", 0);
CHECK_LOG_CTX("Augment target node \"/hi:func/output\" from module \"hh\" was not found.", "/hh:{augment='/hi:func/output'}", 0);
+ CHECK_LOG_CTX("Augment target node \"/hi:func/input\" from module \"hh\" was not found.", "/hh:{augment='/hi:func/input'}", 0);
}
static void
@@ -3133,11 +3104,11 @@ test_deviation(void **state)
assert_non_null(node = mod->compiled->data);
assert_string_equal("c1", node->name);
assert_int_equal(2, LY_ARRAY_COUNT(((struct lysc_node_leaf *)node)->musts));
- assert_string_equal("3", ((struct lysc_node_leaf *)node)->musts[1].cond->expr);
+ assert_string_equal("3", lyxp_get_expr(((struct lysc_node_leaf *)node)->musts[1].cond));
assert_non_null(node = node->next);
assert_string_equal("c2", node->name);
assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_node_container *)node)->musts));
- assert_string_equal("1", ((struct lysc_node_container *)node)->musts[0].cond->expr);
+ assert_string_equal("1", lyxp_get_expr(((struct lysc_node_container *)node)->musts[0].cond));
assert_non_null(node = node->next);
assert_string_equal("c3", node->name);
assert_null(((struct lysc_node_leaf *)node)->musts);
diff --git a/tests/utests/schema/test_yang.c b/tests/utests/schema/test_yang.c
index 5f7b2751e6..8a69b12bdb 100644
--- a/tests/utests/schema/test_yang.c
+++ b/tests/utests/schema/test_yang.c
@@ -18,493 +18,274 @@
#include
#include
-#include "in_internal.h"
-#include "ly_common.h"
-#include "parser_internal.h"
-#include "schema_compile.h"
#include "tree_edit.h"
#include "tree_schema.h"
-#include "tree_schema_free.h"
-
-/* originally static functions from parser_yang.c and parser_yin.c */
-LY_ERR buf_add_char(struct ly_ctx *ctx, struct ly_in *in, size_t len, char **buf, size_t *buf_len, size_t *buf_used);
-LY_ERR buf_store_char(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p,
- size_t *word_len, char **word_b, size_t *buf_len, uint8_t need_buf, uint8_t *prefix);
-LY_ERR get_keyword(struct lysp_yang_ctx *ctx, enum ly_stmt *kw, char **word_p, size_t *word_len);
-LY_ERR get_argument(struct lysp_yang_ctx *ctx, enum yang_arg arg,
- uint16_t *flags, char **word_p, char **word_b, size_t *word_len);
-LY_ERR skip_comment(struct lysp_yang_ctx *ctx, uint8_t comment);
-
-LY_ERR parse_action(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node_action **actions);
-LY_ERR parse_any(struct lysp_yang_ctx *ctx, enum ly_stmt kw, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_augment(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node_augment **augments);
-LY_ERR parse_case(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_container(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_deviate(struct lysp_yang_ctx *ctx, struct lysp_deviate **deviates);
-LY_ERR parse_deviation(struct lysp_yang_ctx *ctx, struct lysp_deviation **deviations);
-LY_ERR parse_grouping(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node_grp **groupings);
-LY_ERR parse_choice(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_leaf(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_leaflist(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_list(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_maxelements(struct lysp_yang_ctx *ctx, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts);
-LY_ERR parse_minelements(struct lysp_yang_ctx *ctx, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts);
-LY_ERR parse_module(struct lysp_yang_ctx *ctx, struct lysp_module *mod);
-LY_ERR parse_notif(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node_notif **notifs);
-LY_ERR parse_submodule(struct lysp_yang_ctx *ctx, struct lysp_submodule *submod);
-LY_ERR parse_uses(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_when(struct lysp_yang_ctx *ctx, struct lysp_when **when_p);
-LY_ERR parse_type_enum_value_pos(struct lysp_yang_ctx *ctx, enum ly_stmt val_kw, struct lysp_type_enum *enm);
-
-struct lysp_yang_ctx *YCTX;
-struct ly_in in = {0};
-
-#define YCTX_INIT \
- in.line = 1; \
- YCTX->in = ∈ \
- LOG_LOCINIT(UTEST_LYCTX, NULL, NULL, NULL, &in)
-
-static int
-setup(void **state)
-{
- struct lysp_module *pmod;
-
- UTEST_SETUP;
-
- /* allocate parser context */
- YCTX = calloc(1, sizeof(*YCTX));
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
- YCTX->format = LYS_IN_YANG;
- ly_set_new(&YCTX->parsed_mods);
-
- /* allocate new parsed module */
- pmod = calloc(1, sizeof *pmod);
- ly_set_add(YCTX->parsed_mods, pmod, 1, NULL);
-
- /* allocate new module */
- pmod->mod = calloc(1, sizeof *pmod->mod);
- pmod->mod->ctx = UTEST_LYCTX;
- pmod->mod->parsed = pmod;
-
- /* initilize and use the global easily available and customizable input handler */
- in.line = 1;
- YCTX->in = ∈
- ly_log_location(NULL, NULL, &in);
-
- return 0;
-}
-static int
-teardown(void **state)
-{
- lys_module_free(PARSER_CTX(YCTX), PARSER_CUR_PMOD(YCTX)->mod, 0);
- ly_log_location_revert(0, 0, 1);
-
- ly_set_free(YCTX->parsed_mods, NULL);
- ly_set_erase(&YCTX->ext_inst, NULL);
- free(YCTX);
- YCTX = NULL;
+#define TEST_MOD(CTX, YANG_STR, EXPECTED_VALUE) \
+ do { \
+ assert_int_equal((EXPECTED_VALUE), lys_parse_mem((CTX), (YANG_STR), LYS_IN_YANG, NULL)); \
+ } while(0)
- UTEST_TEARDOWN;
-
- return 0;
-}
+#define TEST_SUBMOD(CTX, SUBMOD_STR, EXPECTED_VALUE) \
+do { \
+ ly_ctx_set_module_imp_clb((CTX), test_imp_clb, (SUBMOD_STR)); \
+ const char *parent_str = "module parent { yang-version 1.1; namespace \"urn:parent\"; prefix p; include subname; }"; \
+ assert_int_equal((EXPECTED_VALUE), lys_parse_mem((CTX), parent_str, LYS_IN_YANG, NULL)); \
+} while(0)
-#define TEST_DUP_GENERIC(PREFIX, MEMBER, VALUE1, VALUE2, FUNC, RESULT, LINE, CLEANUP) \
- in.current = PREFIX MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, FUNC(YCTX, RESULT)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, LINE);\
- CLEANUP
static void
test_helpers(void **state)
{
- char *buf, *p;
- size_t len, size;
- uint8_t prefix = 0;
-
- /* storing into buffer */
- in.current = "abcd";
- buf = NULL;
- size = len = 0;
- assert_int_equal(LY_SUCCESS, buf_add_char(NULL, &in, 2, &buf, &size, &len));
- assert_int_not_equal(0, size);
- assert_int_equal(2, len);
- assert_string_equal("cd", in.current);
- assert_false(strncmp("ab", buf, 2));
- free(buf);
- buf = NULL;
-
/* invalid first characters */
- len = 0;
- in.current = "2invalid";
- assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
- in.current = ".invalid";
- assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
- in.current = "-invalid";
- assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module 2invalid { namespace urn:test; prefix t; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid identifier first character '2' (0x0032).", NULL, 1);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module .invalid { namespace urn:test; prefix t; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid identifier first character '.' (0x002e).", NULL, 1);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module -invalid { namespace urn:test; prefix t; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid identifier first character '-' (0x002d).", NULL, 1);
/* invalid following characters */
- len = 3; /* number of characters read before the str content */
- in.current = "!";
- assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
- in.current = ":";
- assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
- UTEST_LOG_CTX_CLEAN;
- /* valid colon for prefixed identifiers */
- len = size = 0;
- p = NULL;
- prefix = 0;
- in.current = "x:id";
- assert_int_equal(LY_SUCCESS, buf_store_char(YCTX, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 0, &prefix));
- assert_int_equal(1, len);
- assert_null(buf);
- assert_string_equal(":id", in.current);
- assert_int_equal('x', p[len - 1]);
- assert_int_equal(LY_SUCCESS, buf_store_char(YCTX, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
- assert_int_equal(2, len);
- assert_string_equal("id", in.current);
- assert_int_equal(':', p[len - 1]);
- free(buf);
- prefix = 0;
-
- /* checking identifiers */
- assert_int_equal(LY_EVALID, lysp_check_identifierchar((struct lysp_ctx *)YCTX, ':', 0, NULL));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module inv!alid { namespace urn:test; prefix t; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid identifier character '!' (0x0021).", NULL, 1);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module inv:alid { namespace urn:test; prefix t; }", LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", NULL, 1);
- assert_int_equal(LY_EVALID, lysp_check_identifierchar((struct lysp_ctx *)YCTX, '#', 1, NULL));
- CHECK_LOG_CTX("Invalid identifier first character '#' (0x0023).", NULL, 1);
-
- assert_int_equal(LY_SUCCESS, lysp_check_identifierchar((struct lysp_ctx *)YCTX, 'a', 1, &prefix));
- assert_int_equal(0, prefix);
- assert_int_equal(LY_SUCCESS, lysp_check_identifierchar((struct lysp_ctx *)YCTX, ':', 0, &prefix));
- assert_int_equal(1, prefix);
- assert_int_equal(LY_EVALID, lysp_check_identifierchar((struct lysp_ctx *)YCTX, ':', 0, &prefix));
+
+ /* valid colon for prefixed identifiers */
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module valid { namespace urn:test; prefix t; typedef my-string { type string; } leaf my-leaf { type t:my-string; } }", LYS_IN_YANG, NULL));
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module invalid { namespace urn:test; prefix t; typedef my-string { type string; } leaf my-leaf { type t::my-string; } }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"invalid\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid identifier first character ':' (0x003a).", NULL, 1);
- assert_int_equal(1, prefix);
- assert_int_equal(LY_SUCCESS, lysp_check_identifierchar((struct lysp_ctx *)YCTX, 'b', 0, &prefix));
- assert_int_equal(2, prefix);
- /* second colon is invalid */
- assert_int_equal(LY_EVALID, lysp_check_identifierchar((struct lysp_ctx *)YCTX, ':', 0, &prefix));
- CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", NULL, 1);
}
-#define TEST_GET_ARGUMENT_SUCCESS(INPUT_TEXT, CTX, ARG_TYPE, EXPECT_WORD, EXPECT_LEN, EXPECT_CURRENT, EXPECT_LINE)\
- {\
- const char * text = INPUT_TEXT;\
- in.line = 1;\
- in.current = text;\
- assert_int_equal(LY_SUCCESS, get_argument(CTX, Y_MAYBE_STR_ARG, NULL, &word, &buf, &len));\
- assert_string_equal(word, EXPECT_WORD);\
- assert_int_equal(len, EXPECT_LEN);\
- assert_string_equal(EXPECT_CURRENT, in.current);\
- assert_int_equal(EXPECT_LINE, in.line);\
- }
-
static void
test_comments(void **state)
{
- char *word, *buf;
- size_t len;
-
- TEST_GET_ARGUMENT_SUCCESS(" // this is a text of / one * line */ comment\nargument;",
- YCTX, Y_STR_ARG, "argument;", 8, ";", 2);
- assert_null(buf);
-
- TEST_GET_ARGUMENT_SUCCESS("/* this is a \n * text // of / block * comment */\"arg\" + \"ume\" \n + \n \"nt\";",
- YCTX, Y_STR_ARG, "argument", 8, ";", 4);
- assert_ptr_equal(buf, word);
- free(word);
-
- in.line = 1;
- in.current = " this is one line comment on last line";
- assert_int_equal(LY_SUCCESS, skip_comment(YCTX, 1));
- assert_true(in.current[0] == '\0');
-
- in.line = 1;
- in.current = " this is a not terminated comment x";
- assert_int_equal(LY_EVALID, skip_comment(YCTX, 2));
+ struct lys_module *mod;
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test1 { // this is a text of / one * line */ comment\nnamespace urn:test1; prefix t1; }", LYS_IN_YANG, NULL));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test2 {/* this is a \n * text // of / block * comment */namespace \"urn:t\" + \"es\" \n + \n \"t2\"; prefix t2;}", LYS_IN_YANG, &mod));
+ assert_string_equal("urn:test2", mod->ns);
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test3 { namespace urn:test3; prefix t3; } // this is one line comment on last line", LYS_IN_YANG, NULL));
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test4 { namespace urn:test4; prefix t4; /* this is a not terminated comment x ", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test4\" failed.", NULL, 0);
CHECK_LOG_CTX("Unexpected end-of-input, non-terminated comment.", NULL, 1);
- assert_true(in.current[0] == '\0');
}
static void
test_arg(void **state)
{
- char *word, *buf;
- size_t len;
+ struct lys_module *mod;
+ const char *schema;
/* missing argument */
- in.current = ";";
- assert_int_equal(LY_SUCCESS, get_argument(YCTX, Y_MAYBE_STR_ARG, NULL, &word, &buf, &len));
- assert_null(word);
-
- in.current = "{";
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_STR_ARG, NULL, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test { namespace urn:test; prefix ; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid character sequence \";\", expected an argument.", NULL, 1);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test { namespace urn:test; prefix {} }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid character sequence \"{\", expected an argument.", NULL, 1);
/* invalid escape sequence */
- in.current = "\"\\s\"";
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_STR_ARG, NULL, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test { namespace urn:test; prefix t; description \"\\s\"; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Double-quoted string unknown special character \'\\s\'.", NULL, 1);
-
- TEST_GET_ARGUMENT_SUCCESS("\'\\s\'", YCTX, Y_STR_ARG, "\\s\'", 2, "", 1);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test { namespace urn:test; prefix t; description \'\\s\'; }", LYS_IN_YANG, NULL));
/* invalid character after the argument */
- in.current = "hello\"";
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_STR_ARG, NULL, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test1 { namespace hello\"; prefix t;}", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test1\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid character sequence \"\"\", expected unquoted string character, optsep, semicolon or opening brace.", NULL, 1);
- in.current = "hello}";
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_STR_ARG, NULL, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test1 { namespace hello}; prefix t;}", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test1\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid character sequence \"}\", expected unquoted string character, optsep, semicolon or opening brace.", NULL, 1);
+
/* invalid identifier-ref-arg-str */
- in.current = "pre:pre:value";
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test1 { namespace urn:test; prefix t; typedef my-string { type string; } leaf my-leaf { type t:t:my-string; } }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test1\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", NULL, 1);
- in.current = "\"\";"; /* empty identifier is not allowed */
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_IDENTIF_ARG, NULL, &word, &buf, &len));
+ /* empty identifier is not allowed */
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test1 { namespace urn:test; prefix \"\"; }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test1\" failed.", NULL, 0);
CHECK_LOG_CTX("Statement argument is required.", NULL, 1);
- in.current = "\"\";"; /* empty reference identifier is not allowed */
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &len));
+ /* empty reference identifier is not allowed */
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test1 { namespace urn:test; prefix t; typedef my-string { type string; } leaf my-leaf { type \"\"; } }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test1\" failed.", NULL, 0);
CHECK_LOG_CTX("Statement argument is required.", NULL, 1);
/* slash is not an invalid character */
- TEST_GET_ARGUMENT_SUCCESS("hello/x\t", YCTX, Y_STR_ARG, "hello/x\t", 7, "\t", 1);
- assert_null(buf);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test1 { namespace urn:test1; prefix t; description \"hello/x\"; }", LYS_IN_YANG, &mod));
+ assert_string_equal("hello/x", mod->dsc);
/* different quoting */
- TEST_GET_ARGUMENT_SUCCESS("hello/x\t", YCTX, Y_STR_ARG, "hello/x\t", 7, "\t", 1);
-
- TEST_GET_ARGUMENT_SUCCESS("hello ", YCTX, Y_STR_ARG, "hello ", 5, " ", 1);
-
- TEST_GET_ARGUMENT_SUCCESS("\"hello\\n\\t\\\"\\\\\";", YCTX, Y_STR_ARG, "hello\n\t\"\\", 9, ";", 1);
- free(buf);
-
- YCTX->indent = 14;
- /* - space and tabs before newline are stripped out
- * - space and tabs after newline (indentation) are stripped out
- */
- TEST_GET_ARGUMENT_SUCCESS("\"hello \t\n\t\t world!\"", YCTX, Y_STR_ARG, "hello\n world!", 14, "", 2);
- free(buf);
-
-/* In contrast to previous, the backslash-escaped tabs are expanded after trimming, so they are preserved */
- YCTX->indent = 14;
- TEST_GET_ARGUMENT_SUCCESS("\"hello \\t\n\t\\t world!\"", YCTX, Y_STR_ARG, "hello \t\n\t world!", 16, "", 2);
- assert_ptr_equal(word, buf);
- free(buf);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test2 { namespace urn:test2; prefix t; description \"hello/x\t\"; }", LYS_IN_YANG, &mod));
+ assert_string_equal("hello/x\t", mod->dsc);
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test3 { namespace urn:test3; prefix t; description \"hello \"; }", LYS_IN_YANG, &mod));
+ assert_string_equal("hello ", mod->dsc);
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module test4 { namespace urn:test4; prefix t; description \"hello\\n\\t\\\"\\\\\"; }", LYS_IN_YANG, &mod));
+ assert_string_equal("hello\n\t\"\\", mod->dsc);
+
+ schema = "module test5 {\n"
+ " namespace urn:test5;\n"
+ " prefix t;\n"
+ " description \"hello \t\n\t\t world!\";\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello\n world!", mod->dsc);
+
+ /* In contrast to previous, the backslash-escaped tabs are expanded after trimming, so they are preserved */
+ schema = "module test6 {\n"
+ " namespace urn:test6;\n"
+ " prefix t;\n"
+ " description \"hello \\t\n\t\\t world!\";\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello \t\n\t world!", mod->dsc);
/* Do not handle whitespaces after backslash-escaped newline as indentation */
- YCTX->indent = 14;
- TEST_GET_ARGUMENT_SUCCESS("\"hello\\n\t\t world!\"", YCTX, Y_STR_ARG, "hello\n\t\t world!", 15, "", 1);
- assert_ptr_equal(word, buf);
- free(buf);
-
- YCTX->indent = 14;
- TEST_GET_ARGUMENT_SUCCESS("\"hello\n \tworld!\"", YCTX, Y_STR_ARG, "hello\nworld!", 12, "", 2);
- assert_ptr_equal(word, buf);
- free(buf);
-
- TEST_GET_ARGUMENT_SUCCESS("\'hello\'", YCTX, Y_STR_ARG, "hello'", 5, "", 1);
-
- TEST_GET_ARGUMENT_SUCCESS("\"hel\" +\t\n\"lo\"", YCTX, Y_STR_ARG, "hello", 5, "", 2);
- assert_ptr_equal(word, buf);
- free(buf);
-
- in.line = 1;
- in.current = "\"hel\" +\t\nlo"; /* unquoted the second part */
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_STR_ARG, NULL, &word, &buf, &len));
- CHECK_LOG_CTX("Both string parts divided by '+' must be quoted.", NULL, 2);
-
- TEST_GET_ARGUMENT_SUCCESS("\'he\'\t\n+ \"llo\"", YCTX, Y_STR_ARG, "hello", 5, "", 2);
- free(buf);
-
- TEST_GET_ARGUMENT_SUCCESS(" \t\n\"he\"+\'llo\'", YCTX, Y_STR_ARG, "hello", 5, "", 2);
- free(buf);
-
- /* missing argument */
- in.line = 1;
- in.current = ";";
- assert_int_equal(LY_EVALID, get_argument(YCTX, Y_STR_ARG, NULL, &word, &buf, &len));
- CHECK_LOG_CTX("Invalid character sequence \";\", expected an argument.", NULL, 1);
+ schema = "module test7 {\n"
+ " namespace urn:test7;\n"
+ " prefix t;\n"
+ " description \"hello\\n\t\t world!\";\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello\n\t\t world!", mod->dsc);
+
+ schema = "module test8 {\n"
+ " namespace urn:test8;\n"
+ " prefix t;\n"
+ " description \"hello\n \tworld!\";\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello\nworld!", mod->dsc);
+
+ schema = "module test9 {\n"
+ " namespace urn:test9;\n"
+ " prefix t;\n"
+ " description \'hello\';\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello", mod->dsc);
+
+ schema = "module test10 {\n"
+ " namespace urn:test10;\n"
+ " prefix t;\n"
+ " description \"hel\" +\t\n\"lo\";\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello", mod->dsc);
+
+ schema = "module test11 {\n"
+ " namespace urn:test11;\n"
+ " prefix t;\n"
+ " description \'he\'\t\n+ \"llo\";\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello", mod->dsc);
+
+ schema = "module test12 {\n"
+ " namespace urn:test12;\n"
+ " prefix t;\n"
+ " description \t\n\"he\"+\'llo\';\n"
+ "}";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_string_equal("hello", mod->dsc);
+
+ schema = "module test13 {\n"
+ " namespace urn:test13;\n"
+ " prefix t;\n"
+ " description \"hel\" +\t\nlo;\n"
+ "}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ CHECK_LOG_CTX("Parsing module \"test13\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Both string parts divided by '+' must be quoted.", NULL, 5);
}
-#define TEST_STMS_SUCCESS(INPUT_TEXT, CTX, ACTION, EXPECT_WORD)\
- in.current = INPUT_TEXT;\
- assert_int_equal(LY_SUCCESS, get_keyword(CTX, &kw, &word, &len));\
- assert_int_equal(ACTION, kw);\
- assert_int_equal(strlen(EXPECT_WORD), len);\
- assert_true(0 == strncmp(EXPECT_WORD, word, len))
+#define TEST_STMS_SUCCESS(CTX, MOD_NAME, STMT_TEXT) \
+ do { \
+ struct lys_module *mod; \
+ char buffer[1024]; \
+ snprintf(buffer, sizeof(buffer), \
+ "module %s { yang-version 1.1; namespace \"urn:test:%s\"; prefix t; %s }", \
+ (MOD_NAME), (MOD_NAME), (STMT_TEXT)); \
+ assert_int_equal(LY_SUCCESS, lys_parse_mem((CTX), buffer, LYS_IN_YANG, &mod)); \
+ } while(0)
static void
test_stmts(void **state)
{
- const char *p;
- enum ly_stmt kw;
- char *word;
- size_t len;
-
- in.current = "\n// comment\n\tinput\t{";
- assert_int_equal(LY_SUCCESS, get_keyword(YCTX, &kw, &word, &len));
- assert_int_equal(LY_STMT_INPUT, kw);
- assert_int_equal(5, len);
- assert_string_equal("input\t{", word);
- assert_string_equal("\t{", in.current);
-
- in.current = "\t /* comment */\t output\n\t{";
- assert_int_equal(LY_SUCCESS, get_keyword(YCTX, &kw, &word, &len));
- assert_int_equal(LY_STMT_OUTPUT, kw);
- assert_int_equal(6, len);
- assert_string_equal("output\n\t{", word);
- assert_string_equal("\n\t{", in.current);
- assert_int_equal(LY_SUCCESS, get_keyword(YCTX, &kw, &word, &len));
- assert_int_equal(LY_STMT_SYNTAX_LEFT_BRACE, kw);
- assert_int_equal(1, len);
- assert_string_equal("{", word);
- assert_string_equal("", in.current);
-
- in.current = "/input { "; /* invalid slash */
- assert_int_equal(LY_EVALID, get_keyword(YCTX, &kw, &word, &len));
- CHECK_LOG_CTX("Invalid identifier first character '/'.", NULL, 4);
-
- in.current = "not-a-statement-nor-extension { "; /* invalid identifier */
- assert_int_equal(LY_EVALID, get_keyword(YCTX, &kw, &word, &len));
- CHECK_LOG_CTX("Invalid character sequence \"not-a-statement-nor-extension\", expected a keyword.", NULL, 4);
-
- in.current = "path;"; /* missing sep after the keyword */
- assert_int_equal(LY_EVALID, get_keyword(YCTX, &kw, &word, &len));
- CHECK_LOG_CTX("Invalid character sequence \"path;\", expected a keyword followed by a separator.", NULL, 4);
-
- TEST_STMS_SUCCESS("action ", YCTX, LY_STMT_ACTION, "action");
-
- TEST_STMS_SUCCESS("anydata ", YCTX, LY_STMT_ANYDATA, "anydata");
- TEST_STMS_SUCCESS("anyxml ", YCTX, LY_STMT_ANYXML, "anyxml");
- TEST_STMS_SUCCESS("argument ", YCTX, LY_STMT_ARGUMENT, "argument");
- TEST_STMS_SUCCESS("augment ", YCTX, LY_STMT_AUGMENT, "augment");
- TEST_STMS_SUCCESS("base ", YCTX, LY_STMT_BASE, "base");
- TEST_STMS_SUCCESS("belongs-to ", YCTX, LY_STMT_BELONGS_TO, "belongs-to");
- TEST_STMS_SUCCESS("bit ", YCTX, LY_STMT_BIT, "bit");
- TEST_STMS_SUCCESS("case ", YCTX, LY_STMT_CASE, "case");
- TEST_STMS_SUCCESS("choice ", YCTX, LY_STMT_CHOICE, "choice");
- TEST_STMS_SUCCESS("config ", YCTX, LY_STMT_CONFIG, "config");
- TEST_STMS_SUCCESS("contact ", YCTX, LY_STMT_CONTACT, "contact");
- TEST_STMS_SUCCESS("container ", YCTX, LY_STMT_CONTAINER, "container");
- TEST_STMS_SUCCESS("default ", YCTX, LY_STMT_DEFAULT, "default");
- TEST_STMS_SUCCESS("description ", YCTX, LY_STMT_DESCRIPTION, "description");
- TEST_STMS_SUCCESS("deviate ", YCTX, LY_STMT_DEVIATE, "deviate");
- TEST_STMS_SUCCESS("deviation ", YCTX, LY_STMT_DEVIATION, "deviation");
- TEST_STMS_SUCCESS("enum ", YCTX, LY_STMT_ENUM, "enum");
- TEST_STMS_SUCCESS("error-app-tag ", YCTX, LY_STMT_ERROR_APP_TAG, "error-app-tag");
- TEST_STMS_SUCCESS("error-message ", YCTX, LY_STMT_ERROR_MESSAGE, "error-message");
- TEST_STMS_SUCCESS("extension ", YCTX, LY_STMT_EXTENSION, "extension");
- TEST_STMS_SUCCESS("feature ", YCTX, LY_STMT_FEATURE, "feature");
- TEST_STMS_SUCCESS("fraction-digits ", YCTX, LY_STMT_FRACTION_DIGITS, "fraction-digits");
- TEST_STMS_SUCCESS("grouping ", YCTX, LY_STMT_GROUPING, "grouping");
- TEST_STMS_SUCCESS("identity ", YCTX, LY_STMT_IDENTITY, "identity");
- TEST_STMS_SUCCESS("if-feature ", YCTX, LY_STMT_IF_FEATURE, "if-feature");
- TEST_STMS_SUCCESS("import ", YCTX, LY_STMT_IMPORT, "import");
- TEST_STMS_SUCCESS("include ", YCTX, LY_STMT_INCLUDE, "include");
- TEST_STMS_SUCCESS("input{", YCTX, LY_STMT_INPUT, "input");
- TEST_STMS_SUCCESS("key ", YCTX, LY_STMT_KEY, "key");
- TEST_STMS_SUCCESS("leaf ", YCTX, LY_STMT_LEAF, "leaf");
- TEST_STMS_SUCCESS("leaf-list ", YCTX, LY_STMT_LEAF_LIST, "leaf-list");
- TEST_STMS_SUCCESS("length ", YCTX, LY_STMT_LENGTH, "length");
- TEST_STMS_SUCCESS("list ", YCTX, LY_STMT_LIST, "list");
- TEST_STMS_SUCCESS("mandatory ", YCTX, LY_STMT_MANDATORY, "mandatory");
- TEST_STMS_SUCCESS("max-elements ", YCTX, LY_STMT_MAX_ELEMENTS, "max-elements");
- TEST_STMS_SUCCESS("min-elements ", YCTX, LY_STMT_MIN_ELEMENTS, "min-elements");
- TEST_STMS_SUCCESS("modifier ", YCTX, LY_STMT_MODIFIER, "modifier");
- TEST_STMS_SUCCESS("module ", YCTX, LY_STMT_MODULE, "module");
- TEST_STMS_SUCCESS("must ", YCTX, LY_STMT_MUST, "must");
- TEST_STMS_SUCCESS("namespace ", YCTX, LY_STMT_NAMESPACE, "namespace");
- TEST_STMS_SUCCESS("notification ", YCTX, LY_STMT_NOTIFICATION, "notification");
- TEST_STMS_SUCCESS("ordered-by ", YCTX, LY_STMT_ORDERED_BY, "ordered-by");
- TEST_STMS_SUCCESS("organization ", YCTX, LY_STMT_ORGANIZATION, "organization");
- TEST_STMS_SUCCESS("output ", YCTX, LY_STMT_OUTPUT, "output");
- TEST_STMS_SUCCESS("path ", YCTX, LY_STMT_PATH, "path");
- TEST_STMS_SUCCESS("pattern ", YCTX, LY_STMT_PATTERN, "pattern");
- TEST_STMS_SUCCESS("position ", YCTX, LY_STMT_POSITION, "position");
- TEST_STMS_SUCCESS("prefix ", YCTX, LY_STMT_PREFIX, "prefix");
- TEST_STMS_SUCCESS("presence ", YCTX, LY_STMT_PRESENCE, "presence");
- TEST_STMS_SUCCESS("range ", YCTX, LY_STMT_RANGE, "range");
- TEST_STMS_SUCCESS("reference ", YCTX, LY_STMT_REFERENCE, "reference");
- TEST_STMS_SUCCESS("refine ", YCTX, LY_STMT_REFINE, "refine");
- TEST_STMS_SUCCESS("require-instance ", YCTX, LY_STMT_REQUIRE_INSTANCE, "require-instance");
- TEST_STMS_SUCCESS("revision ", YCTX, LY_STMT_REVISION, "revision");
- TEST_STMS_SUCCESS("revision-date ", YCTX, LY_STMT_REVISION_DATE, "revision-date");
- TEST_STMS_SUCCESS("rpc ", YCTX, LY_STMT_RPC, "rpc");
- TEST_STMS_SUCCESS("status ", YCTX, LY_STMT_STATUS, "status");
- TEST_STMS_SUCCESS("submodule ", YCTX, LY_STMT_SUBMODULE, "submodule");
- TEST_STMS_SUCCESS("type ", YCTX, LY_STMT_TYPE, "type");
- TEST_STMS_SUCCESS("typedef ", YCTX, LY_STMT_TYPEDEF, "typedef");
- TEST_STMS_SUCCESS("unique ", YCTX, LY_STMT_UNIQUE, "unique");
- TEST_STMS_SUCCESS("units ", YCTX, LY_STMT_UNITS, "units");
- TEST_STMS_SUCCESS("uses ", YCTX, LY_STMT_USES, "uses");
- TEST_STMS_SUCCESS("value ", YCTX, LY_STMT_VALUE, "value");
- TEST_STMS_SUCCESS("when ", YCTX, LY_STMT_WHEN, "when");
- TEST_STMS_SUCCESS("yang-version ", YCTX, LY_STMT_YANG_VERSION, "yang-version");
- TEST_STMS_SUCCESS("yin-element ", YCTX, LY_STMT_YIN_ELEMENT, "yin-element");
- TEST_STMS_SUCCESS(";config false;", YCTX, LY_STMT_SYNTAX_SEMICOLON, ";");
- assert_string_equal("config false;", in.current);
- TEST_STMS_SUCCESS("{ config false;", YCTX, LY_STMT_SYNTAX_LEFT_BRACE, "{");
- assert_string_equal(" config false;", in.current);
- TEST_STMS_SUCCESS("}", YCTX, LY_STMT_SYNTAX_RIGHT_BRACE, "}");
- assert_string_equal("", in.current);
-
- /* geenric extension */
- in.current = p = "nacm:default-deny-write;";
- assert_int_equal(LY_SUCCESS, get_keyword(YCTX, &kw, &word, &len));
- assert_int_equal(LY_STMT_EXTENSION_INSTANCE, kw);
- assert_int_equal(23, len);
- assert_ptr_equal(p, word);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test {namespace \"urn:test:err\"; prefix e; /input { }", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid identifier first character '/'.", NULL, 1);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module test { namespace \"urn:test:err2\"; prefix e2; not-a-statement-nor-extension {}", LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid character sequence \"not-a-statement-nor-extension\", expected a keyword.", NULL, 1);
+
+ TEST_STMS_SUCCESS(UTEST_LYCTX, "t-input-fmt", "rpc my-rpc { \n// comment\n\tinput\t{ leaf in-leaf { type string; } } }");
+ TEST_STMS_SUCCESS(UTEST_LYCTX, "t-output-fmt", "rpc my-rpc { \t /* comment */\t output\n\t{ leaf out-leaf { type string; } } }");
}
static void
test_minmax(void **state)
{
- uint16_t flags = 0;
- uint32_t value = 0;
- struct lysp_ext_instance *ext = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
- in.current = " 1invalid; ...";
- assert_int_equal(LY_EVALID, parse_minelements(YCTX, &value, &flags, &ext));
+ const char *yang =
+ "module test {"
+ " yang-version 1.1;"
+ " namespace \"urn:test\";"
+ " prefix t;"
+ " leaf-list ll {"
+ " type string;"
+ " min-elements %s;"
+ " max-elements %s;"
+ " }"
+ "}";
+ char buf[256];
+
+ snprintf(buf, sizeof buf, yang, "1invalid", "...");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"1invalid\" of \"min-elements\".", NULL, 1);
- flags = value = 0;
- in.current = " -1; ...";
- assert_int_equal(LY_EVALID, parse_minelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "-1", "...");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-1\" of \"min-elements\".", NULL, 1);
/* implementation limit */
- flags = value = 0;
- in.current = " 4294967296; ...";
- assert_int_equal(LY_EVALID, parse_minelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "4294967296", "...");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Value \"4294967296\" is out of \"min-elements\" bounds.", NULL, 1);
- flags = value = 0;
- in.current = " 1 {config true;} ...";
- assert_int_equal(LY_EVALID, parse_minelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "1 {config true;}", "...");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"min-elements\".", NULL, 1);
- in.current = " 1invalid; ...";
- assert_int_equal(LY_EVALID, parse_maxelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "2", "1invalid");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"1invalid\" of \"max-elements\".", NULL, 1);
- flags = value = 0;
- in.current = " -1; ...";
- assert_int_equal(LY_EVALID, parse_maxelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "2", "-1");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-1\" of \"max-elements\".", NULL, 1);
- /* implementation limit */
- flags = value = 0;
- in.current = " 4294967296; ...";
- assert_int_equal(LY_EVALID, parse_maxelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "2", "4294967296");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Value \"4294967296\" is out of \"max-elements\" bounds.", NULL, 1);
- flags = value = 0;
- in.current = " 1 {config true;} ...";
- assert_int_equal(LY_EVALID, parse_maxelements(YCTX, &value, &flags, &ext));
+ snprintf(buf, sizeof buf, yang, "2", "1 {config true;}");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buf, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"max-elements\".", NULL, 1);
}
@@ -712,41 +493,6 @@ test_valid_module(void **state)
free(printed);
}
-static struct lysp_module *
-mod_renew(struct lysp_yang_ctx *ctx)
-{
- struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
- struct lysp_module *pmod;
-
- lys_module_free(PARSER_CTX(YCTX), PARSER_CUR_PMOD(ctx)->mod, 0);
- pmod = calloc(1, sizeof *pmod);
- ctx->parsed_mods->objs[0] = pmod;
- pmod->mod = calloc(1, sizeof *pmod->mod);
- pmod->mod->parsed = pmod;
- pmod->mod->ctx = ly_ctx;
-
- ctx->in->line = 1;
-
- return pmod;
-}
-
-static struct lysp_submodule *
-submod_renew(struct lysp_yang_ctx *ctx)
-{
- struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
- struct lysp_submodule *submod;
-
- lys_module_free(PARSER_CTX(YCTX), PARSER_CUR_PMOD(ctx)->mod, 0);
- submod = calloc(1, sizeof *submod);
- ctx->parsed_mods->objs[0] = submod;
- submod->mod = calloc(1, sizeof *submod->mod);
- lysdict_insert(ly_ctx, "name", 0, &submod->mod->name);
- submod->mod->parsed = (struct lysp_module *)submod;
- submod->mod->ctx = ly_ctx;
-
- return submod;
-}
-
static LY_ERR
test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name),
const char *UNUSED(sub_rev), void *user_data, LYS_INFORMAT *format,
@@ -761,306 +507,154 @@ test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const ch
static void
test_module(void **state)
{
- struct lysp_module *mod = NULL;
- struct lysp_submodule *submod = NULL;
- struct lys_module *m;
- struct lysp_yang_ctx *ctx_p;
-
- mod = mod_renew(YCTX);
-
- /* missing mandatory substatements */
- in.current = " name {}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- assert_string_equal("name", mod->mod->name);
+ /* Missing mandatory substatements */
+ TEST_MOD(UTEST_LYCTX, "module name {}", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory keyword \"namespace\" as a child of \"module\".", NULL, 1);
-
- mod = mod_renew(YCTX);
- in.current = " name {namespace urn:name;}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- assert_string_equal("urn:name", mod->mod->ns);
+ TEST_MOD(UTEST_LYCTX, "module name { namespace urn:name; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory keyword \"prefix\" as a child of \"module\".", NULL, 1);
- mod = mod_renew(YCTX);
-
- in.current = " name {namespace urn:name;prefix \"n\";}";
- assert_int_equal(LY_SUCCESS, parse_module(YCTX, mod));
- assert_string_equal("n", mod->mod->prefix);
- mod = mod_renew(YCTX);
-
-#define SCHEMA_BEGINNING " name {yang-version 1.1;namespace urn:x;prefix \"x\";"
-#define SCHEMA_BEGINNING2 " name {namespace urn:x;prefix \"x\";"
-#define TEST_NODE(NODETYPE, INPUT, NAME) \
- in.current = SCHEMA_BEGINNING INPUT; \
- assert_int_equal(LY_SUCCESS, parse_module(YCTX, mod)); \
- assert_non_null(mod->data); \
- assert_int_equal(NODETYPE, mod->data->nodetype); \
- assert_string_equal(NAME, mod->data->name); \
- mod = mod_renew(YCTX);
-#define TEST_GENERIC(INPUT, TARGET, TEST) \
- in.current = SCHEMA_BEGINNING INPUT; \
- assert_int_equal(LY_SUCCESS, parse_module(YCTX, mod)); \
- assert_non_null(TARGET); \
- TEST; \
- mod = mod_renew(YCTX);
-#define TEST_DUP(MEMBER, VALUE1, VALUE2, LINE) \
- TEST_DUP_GENERIC(SCHEMA_BEGINNING, MEMBER, VALUE1, VALUE2, \
- parse_module, mod, LINE, mod = mod_renew(YCTX))
-
- /* duplicated namespace, prefix */
- TEST_DUP("namespace", "y", "z", 1);
- TEST_DUP("prefix", "y", "z", 1);
- TEST_DUP("contact", "a", "b", 1);
- TEST_DUP("description", "a", "b", 1);
- TEST_DUP("organization", "a", "b", 1);
- TEST_DUP("reference", "a", "b", 1);
-
- /* not allowed in module (submodule-specific) */
- in.current = SCHEMA_BEGINNING "belongs-to master {prefix m;}}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- CHECK_LOG_CTX("Invalid keyword \"belongs-to\" as a child of \"module\".", NULL, 1);
- mod = mod_renew(YCTX);
-
- /* anydata */
- TEST_NODE(LYS_ANYDATA, "anydata test;}", "test");
- /* anyxml */
- TEST_NODE(LYS_ANYXML, "anyxml test;}", "test");
- /* augment */
- TEST_GENERIC("augment /somepath;}", mod->augments,
- assert_string_equal("/somepath", mod->augments[0].nodeid));
- /* choice */
- TEST_NODE(LYS_CHOICE, "choice test;}", "test");
- /* contact 0..1 */
- TEST_GENERIC("contact \"firstname\" + \n\t\" surname\";}", mod->mod->contact,
- assert_string_equal("firstname surname", mod->mod->contact));
- /* container */
- TEST_NODE(LYS_CONTAINER, "container test;}", "test");
- /* description 0..1 */
- TEST_GENERIC("description \'some description\';}", mod->mod->dsc,
- assert_string_equal("some description", mod->mod->dsc));
- /* deviation */
- TEST_GENERIC("deviation /somepath {deviate not-supported;}}", mod->deviations,
- assert_string_equal("/somepath", mod->deviations[0].nodeid));
- /* extension */
- TEST_GENERIC("extension test;}", mod->extensions,
- assert_string_equal("test", mod->extensions[0].name));
- /* feature */
- TEST_GENERIC("feature test;}", mod->features,
- assert_string_equal("test", mod->features[0].name));
- /* grouping */
- TEST_GENERIC("grouping grp;}", mod->groupings,
- assert_string_equal("grp", mod->groupings[0].name));
- /* identity */
- TEST_GENERIC("identity test;}", mod->identities,
- assert_string_equal("test", mod->identities[0].name));
- /* import */
- ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "module zzz { namespace urn:zzz; prefix z;}");
- TEST_GENERIC("import zzz {prefix z;}}", mod->imports,
- assert_string_equal("zzz", mod->imports[0].name));
-
- /* import - prefix collision */
- in.current = SCHEMA_BEGINNING "import zzz {prefix x;}}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- CHECK_LOG_CTX("Prefix \"x\" already used as module prefix.", NULL, 1);
- mod = mod_renew(YCTX);
-
- in.current = SCHEMA_BEGINNING "import zzz {prefix y;}import zzz {prefix y;}}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- CHECK_LOG_CTX("Prefix \"y\" already used to import \"zzz\" module.", NULL, 1);
-
- mod = mod_renew(YCTX);
- ly_log_location_revert(0, 0, 1);
-
- in.current = "module name10 {yang-version 1.1;namespace urn:name10;prefix \"n10\";import zzz {prefix y;}import zzz {prefix z;}}";
- assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_SUCCESS);
- CHECK_LOG_CTX("Single revision of the module \"zzz\" imported twice.", NULL, 0);
- /* include */
- ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "module xxx { namespace urn:xxx; prefix x;}");
- in.current = "module" SCHEMA_BEGINNING "include xxx;}";
- assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EINVAL);
- CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, 0);
- CHECK_LOG_CTX("Parsing submodule \"xxx\" failed.", NULL, 0);
- CHECK_LOG_CTX("Input data contains module in situation when a submodule is expected.", NULL, 0);
+ /* Successful minimal module */
+ TEST_MOD(UTEST_LYCTX, "module name { namespace urn:name; prefix n; }", LY_SUCCESS);
+
+ /* Duplicated headers */
+ TEST_MOD(UTEST_LYCTX, "module dup { namespace urn:x; prefix x; namespace urn:y; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"dup\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"namespace\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module dup { namespace urn:x; prefix x; prefix y; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"dup\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"prefix\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module dup { namespace urn:x; prefix x; contact a; contact b; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"dup\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"contact\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module dup { namespace urn:x; prefix x; description a; description b; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"dup\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"description\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module dup { namespace urn:x; prefix x; organization a; organization b; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"dup\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"organization\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module dup { namespace urn:x; prefix x; reference a; reference b; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"dup\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"reference\".", NULL, 1);
- ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to wrong-name {prefix w;}}");
- in.current = "module" SCHEMA_BEGINNING "include xxx;}";
- assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
- CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, 0);
- CHECK_LOG_CTX("Parsing submodule \"xxx\" failed.", NULL, 0);
- UTEST_LOG_CTX_CLEAN;
-
- ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to name {prefix x;}}");
- TEST_GENERIC("include xxx;}", mod->includes,
- assert_string_equal("xxx", mod->includes[0].name));
-
- /* leaf */
- TEST_NODE(LYS_LEAF, "leaf test {type string;}}", "test");
- /* leaf-list */
- TEST_NODE(LYS_LEAFLIST, "leaf-list test {type string;}}", "test");
- /* list */
- TEST_NODE(LYS_LIST, "list test {key a;leaf a {type string;}}}", "test");
- /* notification */
- TEST_GENERIC("notification test;}", mod->notifs,
- assert_string_equal("test", mod->notifs[0].name));
- /* organization 0..1 */
- TEST_GENERIC("organization \"CESNET a.l.e.\";}", mod->mod->org,
- assert_string_equal("CESNET a.l.e.", mod->mod->org));
- /* reference 0..1 */
- TEST_GENERIC("reference RFC7950;}", mod->mod->ref,
- assert_string_equal("RFC7950", mod->mod->ref));
- /* revision */
- TEST_GENERIC("revision 2018-10-12;}", mod->revs,
- assert_string_equal("2018-10-12", mod->revs[0].date));
- /* rpc */
- TEST_GENERIC("rpc test;}", mod->rpcs,
- assert_string_equal("test", mod->rpcs[0].name));
- /* typedef */
- TEST_GENERIC("typedef test{type string;}}", mod->typedefs,
- assert_string_equal("test", mod->typedefs[0].name));
- /* uses */
- TEST_NODE(LYS_USES, "uses test;}", "test");
- /* yang-version */
- in.current = SCHEMA_BEGINNING2 "\n\tyang-version 10;}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- CHECK_LOG_CTX("Invalid value \"10\" of \"yang-version\".", NULL, 0);
- mod = mod_renew(YCTX);
- in.current = SCHEMA_BEGINNING2 "yang-version 1;yang-version 1.1;}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- CHECK_LOG_CTX("Duplicate keyword \"yang-version\".", NULL, 0);
- mod = mod_renew(YCTX);
- in.current = SCHEMA_BEGINNING2 "yang-version 1;}";
- assert_int_equal(LY_SUCCESS, parse_module(YCTX, mod));
- assert_int_equal(1, mod->version);
- mod = mod_renew(YCTX);
- in.current = SCHEMA_BEGINNING2 "yang-version \"1.1\";}";
- assert_int_equal(LY_SUCCESS, parse_module(YCTX, mod));
- assert_int_equal(2, mod->version);
- mod = mod_renew(YCTX);
-
- in.current = "module " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
- m = calloc(1, sizeof *m);
- m->ctx = PARSER_CUR_PMOD(YCTX)->mod->ctx;
- assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, &in, m));
- CHECK_LOG_CTX("Trailing garbage \"module q {names...\" after module, expected end-of-input.", NULL, 1);
- lysp_yang_ctx_free(ctx_p);
- lys_module_free(PARSER_CTX(YCTX), m, 0);
-
- in.current = "prefix " SCHEMA_BEGINNING "}";
- m = calloc(1, sizeof *m);
- m->ctx = PARSER_CUR_PMOD(YCTX)->mod->ctx;
- assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, &in, m));
+ /* Invalid Keywords in Module (Submodule-specific or illegal) */
+ TEST_MOD(UTEST_LYCTX, "module inv { namespace urn:x; prefix x; belongs-to master { prefix m; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"inv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid keyword \"belongs-to\" as a child of \"module\".", NULL, 1);
+
+ TEST_MOD(UTEST_LYCTX, "module inv { namespace urn:x; prefix x; must false; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"inv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid keyword \"must\" as a child of \"module\".", NULL, 1);
+
+ /* Yang-version parsing and validation */
+ TEST_MOD(UTEST_LYCTX, "module yv { yang-version 10; namespace urn:x; prefix x; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"yv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid value \"10\" of \"yang-version\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module yv { yang-version 1.1; yang-version 1.1; namespace urn:x; prefix x; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"yv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"yang-version\".", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "module yv { yang-version 1; namespace urn:x; prefix x; }", LY_SUCCESS);
+ TEST_MOD(UTEST_LYCTX, "module yv { yang-version \"1.1\"; namespace \"urn:yv4\"; prefix \"yv4\";}", LY_SUCCESS);
+
+ /* Trailing Garbage and Base Syntax */
+ TEST_MOD(UTEST_LYCTX, "module tg1 { namespace urn:x; prefix x; } module q { namespace urn:q; prefix q; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"tg1\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Trailing garbage \"module q { name...\" after module, expected end-of-input.", NULL, 1);
+ TEST_MOD(UTEST_LYCTX, "prefix name { }", LY_EVALID);
CHECK_LOG_CTX("Invalid keyword \"prefix\", expected \"module\" or \"submodule\".", NULL, 1);
- lysp_yang_ctx_free(ctx_p);
- lys_module_free(PARSER_CTX(YCTX), m, 0);
-
- in.current = "module " SCHEMA_BEGINNING "leaf enum {type enumeration {enum seven { position 7;}}}}";
- m = calloc(1, sizeof *m);
- m->ctx = PARSER_CUR_PMOD(YCTX)->mod->ctx;
- assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, &in, m));
- CHECK_LOG_CTX("Invalid keyword \"position\" as a child of \"enum\".", NULL, 1);
- lysp_yang_ctx_free(ctx_p);
- lys_module_free(PARSER_CTX(YCTX), m, 0);
-
- /* extensions */
- TEST_GENERIC("prefix:test;}", mod->exts,
- assert_string_equal("prefix:test", mod->exts[0].name);
- assert_int_equal(LY_STMT_MODULE, mod->exts[0].parent_stmt));
- mod = mod_renew(YCTX);
- /* invalid substatement */
- in.current = SCHEMA_BEGINNING "must false;}";
- assert_int_equal(LY_EVALID, parse_module(YCTX, mod));
- CHECK_LOG_CTX("Invalid keyword \"must\" as a child of \"module\".", NULL, 0);
-
- /* submodule */
- submod = submod_renew(YCTX);
-
- /* missing mandatory substatements */
- in.current = " subname {}";
- assert_int_equal(LY_EVALID, parse_submodule(YCTX, submod));
- CHECK_LOG_CTX("Missing mandatory keyword \"belongs-to\" as a child of \"submodule\".", NULL, 0);
- assert_string_equal("subname", submod->name);
-
- submod = submod_renew(YCTX);
-
- in.current = " subname {belongs-to name {prefix x;}}";
- assert_int_equal(LY_SUCCESS, parse_submodule(YCTX, submod));
- assert_string_equal("name", submod->mod->name);
- submod = submod_renew(YCTX);
-
-#undef SCHEMA_BEGINNING
-#define SCHEMA_BEGINNING " subname {belongs-to name {prefix x;}"
-
- /* duplicated namespace, prefix */
- in.current = " subname {belongs-to name {prefix x;}belongs-to module1;belongs-to module2;} ...";
- assert_int_equal(LY_EVALID, parse_submodule(YCTX, submod));
- CHECK_LOG_CTX("Duplicate keyword \"belongs-to\".", NULL, 0);
- submod = submod_renew(YCTX);
-
- /* not allowed in submodule (module-specific) */
- in.current = SCHEMA_BEGINNING "namespace \"urn:z\";}";
- assert_int_equal(LY_EVALID, parse_submodule(YCTX, submod));
- CHECK_LOG_CTX("Invalid keyword \"namespace\" as a child of \"submodule\".", NULL, 0);
- submod = submod_renew(YCTX);
- in.current = SCHEMA_BEGINNING "prefix m;}}";
- assert_int_equal(LY_EVALID, parse_submodule(YCTX, submod));
- CHECK_LOG_CTX("Invalid keyword \"prefix\" as a child of \"submodule\".", NULL, 0);
- submod = submod_renew(YCTX);
-
- in.current = "submodule " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
- assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_ctx *)YCTX, YCTX->in, &submod));
- CHECK_LOG_CTX("Trailing garbage \"module q {names...\" after submodule, expected end-of-input.", NULL, 1);
- lysp_yang_ctx_free(ctx_p);
-
- in.current = "prefix " SCHEMA_BEGINNING "}";
- assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_ctx *)YCTX, YCTX->in, &submod));
+ /* Submodules */
+ TEST_SUBMOD(UTEST_LYCTX, "submodule subname {}", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"subname\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Missing mandatory keyword \"belongs-to\" as a child of \"submodule\".", NULL, 1);
+ TEST_SUBMOD(UTEST_LYCTX, "submodule subname { belongs-to parent { prefix p; } belongs-to parent2; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"subname\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"belongs-to\".", NULL, 1);
+ TEST_SUBMOD(UTEST_LYCTX, "submodule subname { belongs-to parent { prefix p; } namespace \"urn:z\"; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"subname\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid keyword \"namespace\" as a child of \"submodule\".", NULL, 1);
+ TEST_SUBMOD(UTEST_LYCTX, "submodule subname { belongs-to parent { prefix p; } prefix m; }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"subname\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid keyword \"prefix\" as a child of \"submodule\".", NULL, 1);
+ TEST_SUBMOD(UTEST_LYCTX, "submodule subname { belongs-to parent { prefix p; } } module q {}", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"subname\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Trailing garbage \"module q {}\" after submodule, expected end-of-input.", NULL, 1);
+ TEST_SUBMOD(UTEST_LYCTX, "prefix subname { belongs-to parent { prefix p; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"subname\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"prefix\", expected \"module\" or \"submodule\".", NULL, 1);
- lysp_yang_ctx_free(ctx_p);
- submod = submod_renew(YCTX);
-#undef TEST_GENERIC
-#undef TEST_NODE
-#undef TEST_DUP
-#undef SCHEMA_BEGINNING
+ TEST_SUBMOD(UTEST_LYCTX, "submodule subname { belongs-to parent { prefix p; } }", LY_SUCCESS);
+
+ /* Pre-load modules required for the Import tests */
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module zzz { yang-version 1.1; namespace \"urn:zzz\"; prefix z; }", LYS_IN_YANG, NULL));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module yyy { yang-version 1.1; namespace \"urn:yyy\"; prefix y; }", LYS_IN_YANG, NULL));
+
+ /* Imports */
+ TEST_MOD(UTEST_LYCTX, "module imp-success { namespace urn:s1; prefix s1; import zzz { prefix my-z; } }", LY_SUCCESS);
+ TEST_MOD(UTEST_LYCTX, "module imp-multi { namespace urn:s2; prefix s2; import zzz { prefix z; } import yyy { prefix y; } }", LY_SUCCESS);
+ TEST_MOD(UTEST_LYCTX, "module imp { namespace urn:e4; prefix e4; import zzz { prefix a; } import zzz { prefix b; } }", LY_SUCCESS);
+ CHECK_LOG_CTX("Single revision of the module \"zzz\" imported twice.", NULL, 0);
+ TEST_MOD(UTEST_LYCTX, "module err { namespace urn:e1; prefix e1; import missing-mod { prefix m; } }", LY_EINVAL);
+ CHECK_LOG_CTX("Parsing module \"err\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0);
+ TEST_MOD(UTEST_LYCTX, "module err { namespace urn:e2; prefix e2; import zzz { prefix x; } import yyy { prefix x; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"err\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Prefix \"x\" already used to import \"zzz\" module.", NULL, 1);
+
+ TEST_MOD(UTEST_LYCTX, "module err { namespace urn:e3; prefix z; import zzz { prefix z; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"err\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Prefix \"z\" already used as module prefix.", NULL, 1);
}
static void
test_deviation(void **state)
{
- struct lysp_deviation *d = NULL;
-
/* invalid cardinality */
- TEST_DUP_GENERIC(" test {deviate not-supported;", "description", "a", "b", parse_deviation, &d, 1, );
- TEST_DUP_GENERIC(" test {deviate not-supported;", "reference", "a", "b", parse_deviation, &d, 1, );
+ TEST_MOD(UTEST_LYCTX, "module d1 { namespace urn:d1; prefix d; deviation /d:target { deviate not-supported; description \"a\"; description \"b\"; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"d1\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"description\".", NULL, 1);
+
+ TEST_MOD(UTEST_LYCTX, "module d2 { namespace urn:d2; prefix d; deviation /d:target { deviate not-supported; reference \"a\"; reference \"b\"; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"d2\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"reference\".", NULL, 1);
/* missing mandatory substatement */
- in.current = " test {description text;}";
- assert_int_equal(LY_EVALID, parse_deviation(YCTX, &d));
+ TEST_MOD(UTEST_LYCTX, "module d3 { namespace urn:d3; prefix d; deviation /d:target { description \"text\"; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"d3\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory keyword \"deviate\" as a child of \"deviation\".", NULL, 1);
/* invalid substatement */
- in.current = " test {deviate not-supported; status obsolete;}";
- assert_int_equal(LY_EVALID, parse_deviation(YCTX, &d));
+ TEST_MOD(UTEST_LYCTX, "module d4 { namespace urn:d4; prefix d; deviation /d:target { deviate not-supported; status obsolete; } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"d4\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"status\" as a child of \"deviation\".", NULL, 1);
}
static void
test_deviate(void **state)
{
- struct lysp_deviate *d = NULL;
+#define TEST_DEVIATE_ERR(MEMBER, ERR_MSG) \
+ TEST_MOD(UTEST_LYCTX, "module dev { yang-version 1.1; namespace urn:cont; prefix c; deviation /c:t { " MEMBER " } }", LY_EVALID); \
+ CHECK_LOG_CTX("Parsing module \"dev\" failed.", NULL, 0);\
+ CHECK_LOG_CTX(ERR_MSG, NULL, 1)
/* invalid cardinality */
- TEST_DUP_GENERIC("add {", "config", "true", "false", parse_deviate, &d, 1, );
- TEST_DUP_GENERIC("add {", "mandatory", "true", "false", parse_deviate, &d, 1, );
- TEST_DUP_GENERIC("add {", "max-elements", "1", "2", parse_deviate, &d, 1, );
- TEST_DUP_GENERIC("add {", "min-elements", "1", "2", parse_deviate, &d, 1, );
- TEST_DUP_GENERIC("add {", "units", "kilometers", "miles", parse_deviate, &d, 1, );
+ TEST_DEVIATE_ERR("deviate add { config true; config false; }", "Duplicate keyword \"config\".");
+ TEST_DEVIATE_ERR("deviate add { mandatory true; mandatory false; }", "Duplicate keyword \"mandatory\".");
+ TEST_DEVIATE_ERR("deviate add { max-elements 1; max-elements 2; }", "Duplicate keyword \"max-elements\".");
+ TEST_DEVIATE_ERR("deviate add { min-elements 1; min-elements 2; }", "Duplicate keyword \"min-elements\".");
+ TEST_DEVIATE_ERR("deviate add { units \"kilometers\"; units \"miles\"; }", "Duplicate keyword \"units\".");
- /* invalid substatements */
#define TEST_NOT_SUP(DEV, STMT, VALUE) \
- in.current = " "DEV" {"STMT" "VALUE";}..."; \
- assert_int_equal(LY_EVALID, parse_deviate(YCTX, &d)); \
- CHECK_LOG_CTX("Deviate \""DEV"\" does not support keyword \""STMT"\".", NULL, 1);
+ TEST_DEVIATE_ERR("deviate "DEV" {"STMT" "VALUE";}", "Deviate \""DEV"\" does not support keyword \""STMT"\".");
+ /* invalid substatements */
TEST_NOT_SUP("not-supported", "units", "meters");
TEST_NOT_SUP("not-supported", "must", "1");
TEST_NOT_SUP("not-supported", "unique", "x");
@@ -1078,635 +672,817 @@ test_deviate(void **state)
TEST_NOT_SUP("delete", "type", "string");
TEST_NOT_SUP("replace", "must", "1");
TEST_NOT_SUP("replace", "unique", "a");
-
- in.current = " nonsence; ...";
- assert_int_equal(LY_EVALID, parse_deviate(YCTX, &d));
- CHECK_LOG_CTX("Invalid value \"nonsence\" of \"deviate\".", NULL, 1);\
- assert_null(d);
-#undef TEST_NOT_SUP
+#undef TEST_DEVIATE_ERR
}
static void
test_container(void **state)
{
- struct lysp_node_container *c = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "cont {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node**)&c)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)c); c = NULL;
+ TEST_MOD(UTEST_LYCTX, "module cont { yang-version 1.1; namespace urn:cont; prefix c; container test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} }", LY_EVALID); \
+ CHECK_LOG_CTX("Parsing module \"cont\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
TEST_DUP("config", "true", "false");
- TEST_DUP("description", "text1", "text2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
TEST_DUP("presence", "true", "false");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content */
- in.current = "cont {action x;anydata any;anyxml anyxml; choice ch;config false;container c;description test;grouping g;if-feature f; leaf l {type string;}"
- "leaf-list ll {type string;} list li;must 'expr';notification not; presence true; reference test;status current;typedef t {type int8;}uses g;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_container(YCTX, NULL, (struct lysp_node **)&c));
- CHECK_LYSP_NODE(c, "test", 1, LYS_CONFIG_R | LYS_STATUS_CURR, 1, "cont", 0, LYS_CONTAINER, 0, "test", 1);
- assert_non_null(c->actions);
- assert_non_null(c->child);
- assert_non_null(c->groupings);
- assert_non_null(c->musts);
- assert_non_null(c->notifs);
- assert_string_equal("true", c->presence);
- assert_non_null(c->typedefs);
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- ly_set_erase(&YCTX->grps_nodes, NULL);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)c); c = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module cont {"
+ " yang-version 1.1;"
+ " namespace \"urn:cont\";"
+ " prefix c;"
+ " feature f;"
+ " extension ext;"
+ " container test {"
+ " action x;"
+ " anydata any;"
+ " anyxml anyxml;"
+ " choice ch;"
+ " config false;"
+ " container c;"
+ " description test;"
+ " grouping g;"
+ " if-feature f;"
+ " leaf l {type string;}"
+ " leaf-list ll {type string;}"
+ " list li;"
+ " must 'expr';"
+ " notification not;"
+ " presence true;"
+ " reference test;"
+ " status current;"
+ " typedef t {type int8;}"
+ " uses g;"
+ " when 'true()';"
+ " c:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid */
- in.current = " cont {augment /root;} ...";
- assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node **)&c));
+ TEST_MOD(UTEST_LYCTX, "module cont2 { yang-version 1.1; namespace urn:cont2; prefix c2; container test {augment /root;} }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"cont2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"augment\" as a child of \"container\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)c); c = NULL;
- in.current = " cont {nonsence true;} ...";
- assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node **)&c));
+
+ TEST_MOD(UTEST_LYCTX, "module cont2 { yang-version 1.1; namespace urn:cont2; prefix c2; container test {nonsence true;} }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"cont2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid character sequence \"nonsence\", expected a keyword.", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)c); c = NULL;
- PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 */
- in.current = " cont {action x;} ...";
- assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node **)&c));
+ TEST_MOD(UTEST_LYCTX, "module cont2 { namespace urn:cont2; prefix c2; container test {action x;} }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"cont2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"action\" as a child of \"container\" - "
"the statement is allowed only in YANG 1.1 modules.", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)c); c = NULL;
}
static void
test_leaf(void **state)
{
- struct lysp_node_leaf *l = NULL;
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_leaf(YCTX, NULL, (struct lysp_node**)&l)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)l); l = NULL;
+ TEST_MOD(UTEST_LYCTX, "module leaf1 { namespace urn:leaf1; prefix l1; leaf test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} }", LY_EVALID); \
+ CHECK_LOG_CTX("Parsing module \"leaf1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
TEST_DUP("config", "true", "false");
TEST_DUP("default", "x", "y");
- TEST_DUP("description", "text1", "text2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
TEST_DUP("mandatory", "true", "false");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
TEST_DUP("type", "int8", "uint8");
TEST_DUP("units", "text1", "text2");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content - without mandatory which is mutual exclusive with default */
- in.current = "l {config false;default \"xxx\";description test;if-feature f;"
- "must 'expr';reference test;status current;type string; units yyy;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
- CHECK_LYSP_NODE(l, "test", 1, LYS_CONFIG_R | LYS_STATUS_CURR, 1, "l", 0, LYS_LEAF, 0, "test", 1);
- assert_string_equal("xxx", l->dflt.str);
- assert_string_equal("yyy", l->units);
- assert_string_equal("string", l->type.name);
- assert_non_null(l->musts);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)l); l = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module leaf1 {"
+ " namespace \"urn:leaf1\";"
+ " prefix l1;"
+ " feature f;"
+ " extension ext;"
+ " leaf test {"
+ " config false;"
+ " default \"xxx\";"
+ " description test;"
+ " if-feature f;"
+ " must 'expr';"
+ " reference test;"
+ " status current;"
+ " type string;"
+ " units yyy;"
+ " when 'true()';"
+ " l1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* full content - now with mandatory */
- in.current = "l {mandatory true; type string;} ...";
- assert_int_equal(LY_SUCCESS, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
- CHECK_LYSP_NODE(l, NULL, 0, LYS_MAND_TRUE, 0, "l", 0, LYS_LEAF, 0, NULL, 0);
- assert_string_equal("string", l->type.name);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)l); l = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module leaf2 {"
+ " namespace \"urn:leaf2\";"
+ " prefix l2;"
+ " leaf test {"
+ " mandatory true;"
+ " type string;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid */
- in.current = " l {description \"missing type\";} ...";
- assert_int_equal(LY_EVALID, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
+ TEST_MOD(UTEST_LYCTX, "module leaf3 { namespace urn:leaf3; prefix l3; leaf test {description \"missing type\";} }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"leaf3\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory keyword \"type\" as a child of \"leaf\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)l); l = NULL;
- in.current = "l { type iid { path qpud wrong {";
- assert_int_equal(LY_EVALID, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
+ TEST_MOD(UTEST_LYCTX, "module leaf3 { namespace urn:leaf3; prefix l3; leaf test { type iid { path qpud wrong {} }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"leaf3\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid character sequence \"wrong\", expected a keyword.", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)l); l = NULL;
}
static void
test_leaflist(void **state)
{
- struct lysp_node_leaflist *ll = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "ll {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_leaflist(YCTX, NULL, (struct lysp_node**)&ll)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)ll); ll = NULL;
+ TEST_MOD(UTEST_LYCTX, "module leaflist1 { yang-version 1.1; namespace urn:leaflist1; prefix ll1; leaf-list test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} }", LY_EVALID); \
+ CHECK_LOG_CTX("Parsing module \"leaflist1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
TEST_DUP("config", "true", "false");
- TEST_DUP("description", "text1", "text2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
TEST_DUP("max-elements", "10", "20");
TEST_DUP("min-elements", "10", "20");
TEST_DUP("ordered-by", "user", "system");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
TEST_DUP("type", "int8", "uint8");
TEST_DUP("units", "text1", "text2");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content - without min-elements which is mutual exclusive with default */
- in.current = "ll {config false;default \"xxx\"; default \"yyy\";description test;if-feature f;"
- "max-elements 10;must 'expr';ordered-by user;reference test;"
- "status current;type string; units zzz;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_leaflist(YCTX, NULL, (struct lysp_node **)&ll));
- CHECK_LYSP_NODE(ll, "test", 1, 0x446, 1, "ll", 0, LYS_LEAFLIST, 0, "test", 1);
- assert_non_null(ll->dflts);
- assert_int_equal(2, LY_ARRAY_COUNT(ll->dflts));
- assert_string_equal("xxx", ll->dflts[0].str);
- assert_string_equal("yyy", ll->dflts[1].str);
- assert_string_equal("zzz", ll->units);
- assert_int_equal(10, ll->max);
- assert_int_equal(0, ll->min);
- assert_string_equal("string", ll->type.name);
- assert_non_null(ll->musts);
- assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_USER | LYS_SET_MAX, ll->flags);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)ll); ll = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module leaflist1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:leaflist1\";"
+ " prefix ll1;"
+ " feature f;"
+ " extension ext;"
+ " leaf-list test {"
+ " config false;"
+ " default \"xxx\";"
+ " description test;"
+ " if-feature f;"
+ " max-elements 10;"
+ " must 'expr';"
+ " ordered-by user;"
+ " reference test;"
+ " status current;"
+ " type string;"
+ " units zzz;"
+ " when 'true()';"
+ " ll1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* full content - now with min-elements */
- in.current = "ll {min-elements 10; type string;} ...";
- assert_int_equal(LY_SUCCESS, parse_leaflist(YCTX, NULL, (struct lysp_node **)&ll));
- CHECK_LYSP_NODE(ll, NULL, 0, 0x200, 0, "ll", 0, LYS_LEAFLIST, 0, NULL, 0);
- assert_string_equal("string", ll->type.name);
- assert_int_equal(0, ll->max);
- assert_int_equal(10, ll->min);
- assert_int_equal(LYS_SET_MIN, ll->flags);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)ll); ll = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module leaflist2 {"
+ " yang-version 1.1;"
+ " namespace \"urn:leaflist2\";"
+ " prefix ll2;"
+ " leaf-list test {"
+ " type string;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid */
- in.current = " ll {description \"missing type\";} ...";
- assert_int_equal(LY_EVALID, parse_leaflist(YCTX, NULL, (struct lysp_node **)&ll));
+ TEST_MOD(UTEST_LYCTX, "module leaflist3 { yang-version 1.1; namespace urn:leaflist3; prefix ll3; leaf-list test {description \"missing type\";} }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"leaflist3\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory keyword \"type\" as a child of \"leaf-list\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)ll); ll = NULL;
- PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 - default statement is not allowed */
- in.current = " ll {default xx; type string;} ...";
- assert_int_equal(LY_EVALID, parse_leaflist(YCTX, NULL, (struct lysp_node **)&ll));
+ TEST_MOD(UTEST_LYCTX, "module leaflist3 { namespace urn:leaflist3; prefix ll3; leaf-list test {default xx; type string;}}", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"leaflist3\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"default\" as a child of \"leaf-list\" - the statement is allowed only in YANG 1.1 modules.", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)ll); ll = NULL;
}
static void
test_list(void **state)
{
- struct lysp_node_list *l = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_list(YCTX, NULL, (struct lysp_node**)&l)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)l); l = NULL;
+ TEST_MOD(UTEST_LYCTX, "module list1 { yang-version 1.1; namespace urn:list1; prefix l1; list test {" MEMBER" "VALUE1";"MEMBER" "VALUE2"; key \"name\"; leaf name {type string;}} }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"list1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
TEST_DUP("config", "true", "false");
- TEST_DUP("description", "text1", "text2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
TEST_DUP("key", "one", "two");
TEST_DUP("max-elements", "10", "20");
TEST_DUP("min-elements", "10", "20");
TEST_DUP("ordered-by", "user", "system");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content */
- in.current = "l {action x;anydata any;anyxml anyxml; choice ch;config false;container c;description test;grouping g;if-feature f; key l; leaf l {type string;}"
- "leaf-list ll {type string;} list li;max-elements 10; min-elements 1;must 'expr';notification not; ordered-by system; reference test;"
- "status current;typedef t {type int8;}unique xxx;unique yyy;uses g;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_list(YCTX, NULL, (struct lysp_node **)&l));
- CHECK_LYSP_NODE(l, "test", 1, LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM | LYS_SET_MAX | LYS_SET_MIN, 1, "l",
- 0, LYS_LIST, 0, "test", 1);
- assert_string_equal("l", l->key);
- assert_non_null(l->uniques);
- assert_int_equal(2, LY_ARRAY_COUNT(l->uniques));
- assert_string_equal("xxx", l->uniques[0].str);
- assert_string_equal("yyy", l->uniques[1].str);
- assert_int_equal(10, l->max);
- assert_int_equal(1, l->min);
- assert_non_null(l->musts);
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- ly_set_erase(&YCTX->grps_nodes, NULL);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)l); l = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module list1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:list1\";"
+ " prefix l1;"
+ " feature f;"
+ " extension ext;"
+ " list test {"
+ " action x;"
+ " anydata any;"
+ " anyxml anyxml;"
+ " choice ch;"
+ " config false;"
+ " container c;"
+ " description test;"
+ " grouping g;"
+ " if-feature f;"
+ " key l;"
+ " leaf l {type string;}"
+ " leaf xxx {type string;} "
+ " leaf yyy {type string;} "
+ " leaf-list ll {type string;}"
+ " list li;"
+ " max-elements 10;"
+ " min-elements 1;"
+ " must 'expr';"
+ " notification not;"
+ " ordered-by system;"
+ " reference test;"
+ " status current;"
+ " typedef t {type int8;} unique xxx;"
+ " unique yyy;"
+ " uses g;"
+ " when 'true()';"
+ " l1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid content */
- PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 */
- in.current = "l {action x;} ...";
- assert_int_equal(LY_EVALID, parse_list(YCTX, NULL, (struct lysp_node **)&l));
+ TEST_MOD(UTEST_LYCTX, "module list2 { namespace \"urn:list2\"; prefix l2; list test {action x; key \"name\"; leaf name {type string} } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"list2\" failed.", NULL, 0);\
CHECK_LOG_CTX("Invalid keyword \"action\" as a child of \"list\" - the statement is allowed only in YANG 1.1 modules.", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)l); l = NULL;
}
static void
test_choice(void **state)
{
- struct lysp_node_choice *ch = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "ch {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_choice(YCTX, NULL, (struct lysp_node**)&ch)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)ch); ch = NULL;
+ TEST_MOD(UTEST_LYCTX, "module choice1 { yang-version 1.1; namespace \"urn:choice1\"; prefix c1; choice test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"choice1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
TEST_DUP("config", "true", "false");
TEST_DUP("default", "a", "b");
- TEST_DUP("description", "text1", "text2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
TEST_DUP("mandatory", "true", "false");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content - without default due to a collision with mandatory */
- in.current = "ch {anydata any;anyxml anyxml; case c;choice ch;config false;container c;description test;if-feature f;leaf l {type string;}"
- "leaf-list ll {type string;} list li;mandatory true;reference test;status current;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_choice(YCTX, NULL, (struct lysp_node **)&ch));
- CHECK_LYSP_NODE(ch, "test", 1, LYS_CONFIG_R | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "ch", 0, LYS_CHOICE, 0, "test", 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)ch); ch = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module choice1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:choice1\";"
+ " prefix c1;"
+ " feature f;"
+ " extension ext;"
+ " choice test {"
+ " anydata any;"
+ " anyxml anyxml;"
+ " case c;"
+ " choice ch;"
+ " config false;"
+ " container cont;"
+ " description test;"
+ " if-feature f;"
+ " leaf l {type string;}"
+ " leaf-list ll {type string;}"
+ " list li;"
+ " mandatory true;"
+ " reference test;"
+ " status current;"
+ " when 'true()';"
+ " c1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* full content - the default missing from the previous node */
- in.current = "ch {default c;case c;} ...";
- assert_int_equal(LY_SUCCESS, parse_choice(YCTX, NULL, (struct lysp_node **)&ch));
- CHECK_LYSP_NODE(ch, NULL, 0, 0, 0, "ch", 0, LYS_CHOICE, 0, NULL, 0);
- assert_string_equal("c", ch->dflt.str);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)ch); ch = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module choice2 {"
+ " yang-version 1.1;"
+ " namespace \"urn:choice2\";"
+ " prefix c2;"
+ " choice test {"
+ " default c;"
+ " case c;"
+ " }"
+ "}",
+ LY_SUCCESS);
}
static void
test_case(void **state)
{
- struct lysp_node_case *cs = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "cs {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_case(YCTX, NULL, (struct lysp_node**)&cs)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)cs); cs = NULL;
+ TEST_MOD(UTEST_LYCTX, "module case1 { yang-version 1.1; namespace \"urn:case1\"; prefix c1; choice ch {case test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} } }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"case1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
- TEST_DUP("description", "text1", "text2");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content */
- in.current = "cs {anydata any;anyxml anyxml; choice ch;container c;description test;if-feature f;leaf l {type string;}"
- "leaf-list ll {type string;} list li;reference test;status current;uses grp;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_case(YCTX, NULL, (struct lysp_node **)&cs));
- CHECK_LYSP_NODE(cs, "test", 1, LYS_STATUS_CURR, 1, "cs", 0, LYS_CASE, 0, "test", 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)cs); cs = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module case1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:case1\";"
+ " prefix c1;"
+ " feature f;"
+ " extension ext;"
+ " grouping grp;"
+ " choice ch {"
+ " case test {"
+ " anydata any;"
+ " anyxml anyxml;"
+ " choice cho;"
+ " container cont;"
+ " description test;"
+ " if-feature f;"
+ " leaf l {type string;}"
+ " leaf-list ll {type string;}"
+ " list li { config false; }"
+ " reference test;"
+ " status current;"
+ " uses grp;"
+ " when 'true()';"
+ " c1:ext;"
+ " }"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid content */
- in.current = "cs {config true} ...";
- assert_int_equal(LY_EVALID, parse_case(YCTX, NULL, (struct lysp_node **)&cs));
+ TEST_MOD(UTEST_LYCTX,
+ "module case1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:case1\";"
+ " prefix c1;"
+ " feature f;"
+ " extension ext;"
+ " choice ch {"
+ " case test {"
+ " config true;"
+ " }"
+ " }"
+ "}",
+ LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"case1\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"case\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)cs); cs = NULL;
}
static void
-test_any(void **state, enum ly_stmt kw)
+test_anydata(void **state)
{
- struct lysp_node_anydata *any = NULL;
-
- if (kw == LY_STMT_ANYDATA) {
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
- } else {
- PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 */
- }
-
- /* invalid cardinality */
-#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_any(YCTX, kw, NULL, (struct lysp_node**)&any)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)any); any = NULL;
+ #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+ TEST_MOD(UTEST_LYCTX, "module anydata1 { yang-version 1.1; namespace \"urn:anydata1\"; prefix a1; anydata test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"anydata1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
TEST_DUP("config", "true", "false");
- TEST_DUP("description", "text1", "text2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
TEST_DUP("mandatory", "true", "false");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content */
- in.current = "any {config true;description test;if-feature f;mandatory true;must 'expr';reference test;status current;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_any(YCTX, kw, NULL, (struct lysp_node **)&any));
- // CHECK_LYSP_NODE(NODE, DSC, EXTS, FLAGS, IFFEATURES, NAME, NEXT, TYPE, PARENT, REF, WHEN)
- uint16_t node_type = kw == LY_STMT_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
-
- CHECK_LYSP_NODE(any, "test", 1, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "any", 0, node_type, 0, "test", 1);
- assert_non_null(any->musts);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)any); any = NULL;
-}
-
-static void
-test_anydata(void **state)
-{
- test_any(state, LY_STMT_ANYDATA);
+ TEST_MOD(UTEST_LYCTX,
+ "module anydata1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:anydata1\";"
+ " prefix a1;"
+ " feature f;"
+ " extension ext;"
+ " anydata test {"
+ " config true;"
+ " description test;"
+ " if-feature f;"
+ " mandatory true;"
+ " must 'expr';"
+ " reference test;"
+ " status current;"
+ " when 'true()';"
+ " a1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
}
static void
test_anyxml(void **state)
{
- test_any(state, LY_STMT_ANYXML);
+#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+ TEST_MOD(UTEST_LYCTX, "module anyxml1 { yang-version 1.1; namespace \"urn:anyxml1\"; prefix a1; anyxml test {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"anyxml1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
+
+ TEST_DUP("config", "true", "false");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("mandatory", "true", "false");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
+ TEST_DUP("status", "current", "obsolete");
+ TEST_DUP("when", "'true()'", "'false()'");
+#undef TEST_DUP
+
+ /* full content */
+ TEST_MOD(UTEST_LYCTX,
+ "module anyxml1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:anyxml1\";"
+ " prefix a1;"
+ " feature f;"
+ " extension ext;"
+ " anyxml test {"
+ " config true;"
+ " description test;"
+ " if-feature f;"
+ " mandatory true;"
+ " must 'expr';"
+ " reference test;"
+ " status current;"
+ " when 'true()';"
+ " a1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
}
static void
test_grouping(void **state)
{
- struct lysp_node_grp *grp = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_grouping(YCTX, NULL, &grp)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), &grp->node); grp = NULL;
+ TEST_MOD(UTEST_LYCTX, "module grouping1 { yang-version 1.1; namespace \"urn:group1\"; prefix g1; grouping test {" MEMBER" "VALUE1";"MEMBER" "VALUE2"; leaf name {type string} } }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"grouping1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
- TEST_DUP("description", "text1", "text2");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
#undef TEST_DUP
/* full content */
- in.current = "grp {action x;anydata any;anyxml anyxml; choice ch;container c;description test;grouping g;leaf l {type string;}"
- "leaf-list ll {type string;} list li;notification not;reference test;status current;typedef t {type int8;}uses g;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_grouping(YCTX, NULL, &grp));
- assert_non_null(grp);
- assert_int_equal(LYS_GROUPING, grp->nodetype);
- assert_string_equal("grp", grp->name);
- assert_string_equal("test", grp->dsc);
- assert_non_null(grp->exts);
- assert_string_equal("test", grp->ref);
- assert_null(grp->parent);
- assert_int_equal(LYS_STATUS_CURR, grp->flags);
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- ly_set_erase(&YCTX->grps_nodes, NULL);
- lysp_node_free(PARSER_CTX(YCTX), &grp->node);
- grp = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module grouping1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:grouping1\";"
+ " prefix g1;"
+ " feature f;"
+ " extension ext;"
+ " grouping test {"
+ " anydata any;"
+ " anyxml anyxml;"
+ " choice ch;"
+ " container cont;"
+ " description test;"
+ " grouping g;"
+ " leaf l {type string;}"
+ " leaf-list ll {type string;}"
+ " list li { config false; }"
+ " notification not;"
+ " reference test;"
+ " status current;"
+ " typedef t {type int8;}uses g;"
+ " g1:ext;"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid content */
- in.current = "grp {config true} ...";
- assert_int_equal(LY_EVALID, parse_grouping(YCTX, NULL, &grp));
+ TEST_MOD(UTEST_LYCTX,
+ "module grouping2 {"
+ " yang-version 1.1;"
+ " namespace \"urn:grouping2\";"
+ " prefix g2;"
+ " grouping test {"
+ " config true"
+ " }"
+ "}",
+ LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"grouping2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"grouping\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), &grp->node);
- grp = NULL;
- in.current = "grp {must 'expr'} ...";
- assert_int_equal(LY_EVALID, parse_grouping(YCTX, NULL, &grp));
+ TEST_MOD(UTEST_LYCTX,
+ "module grouping2 {"
+ " yang-version 1.1;"
+ " namespace \"urn:grouping2\";"
+ " prefix g2;"
+ " grouping test {"
+ " must 'expr'"
+ " }"
+ "}",
+ LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"grouping2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"must\" as a child of \"grouping\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), &grp->node);
- grp = NULL;
}
static void
test_action(void **state)
{
- struct lysp_node_action *rpcs = NULL;
- struct lysp_node_container *c = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "func {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_action(YCTX, NULL, &rpcs)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)rpcs); rpcs = NULL;
-
- TEST_DUP("description", "text1", "text2");
- TEST_DUP("input", "{leaf l1 {type empty;}} description a", "{leaf l2 {type empty;}} description a");
- TEST_DUP("output", "{leaf l1 {type empty;}} description a", "{leaf l2 {type empty;}} description a");
- TEST_DUP("reference", "1", "2");
+ TEST_MOD(UTEST_LYCTX, "module act1 { yang-version 1.1; namespace \"urn:act1\"; prefix a; container top { action test { " MEMBER " " VALUE1 "; " MEMBER " " VALUE2 "; } } }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"act1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
+
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
#undef TEST_DUP
+ TEST_MOD(UTEST_LYCTX, "module act1 { yang-version 1.1; namespace \"urn:act-in\"; prefix a; container top { action func { input { leaf l1 {type empty;} } input { leaf l2 {type empty;} } } } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"act1\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"input\".", NULL, 1);
+
+ TEST_MOD(UTEST_LYCTX, "module act1 { yang-version 1.1; namespace \"urn:act-out\"; prefix a; container top { action func { output { leaf l1 {type empty;} } output { leaf l2 {type empty;} } } } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"act1\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Duplicate keyword \"output\".", NULL, 1);
+
/* full content */
- in.current = "top;";
- assert_int_equal(LY_SUCCESS, parse_container(YCTX, NULL, (struct lysp_node **)&c));
- in.current = "func {description test;grouping grp;if-feature f;reference test;status current;typedef mytype {type int8;} m:ext;"
- "input {anydata a1; anyxml a2; choice ch; container c; grouping grp; leaf l {type int8;} leaf-list ll {type int8;}"
- " list li; must 1; typedef mytypei {type int8;} uses grp; m:ext;}"
- "output {anydata a1; anyxml a2; choice ch; container c; grouping grp; leaf l {type int8;} leaf-list ll {type int8;}"
- " list li; must 1; typedef mytypeo {type int8;} uses grp; m:ext;}} ...";
- assert_int_equal(LY_SUCCESS, parse_action(YCTX, (struct lysp_node *)c, &rpcs));
- assert_non_null(rpcs);
- assert_int_equal(LYS_ACTION, rpcs->nodetype);
- assert_string_equal("func", rpcs->name);
- assert_string_equal("test", rpcs->dsc);
- assert_non_null(rpcs->exts);
- assert_non_null(rpcs->iffeatures);
- assert_string_equal("test", rpcs->ref);
- assert_non_null(rpcs->groupings);
- assert_non_null(rpcs->typedefs);
- assert_int_equal(LYS_STATUS_CURR, rpcs->flags);
- /* input */
- assert_int_equal(rpcs->input.nodetype, LYS_INPUT);
- assert_non_null(rpcs->input.groupings);
- assert_non_null(rpcs->input.exts);
- assert_non_null(rpcs->input.musts);
- assert_non_null(rpcs->input.typedefs);
- assert_non_null(rpcs->input.child);
- /* output */
- assert_int_equal(rpcs->output.nodetype, LYS_OUTPUT);
- assert_non_null(rpcs->output.groupings);
- assert_non_null(rpcs->output.exts);
- assert_non_null(rpcs->output.musts);
- assert_non_null(rpcs->output.typedefs);
- assert_non_null(rpcs->output.child);
-
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- ly_set_erase(&YCTX->grps_nodes, NULL);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)rpcs); rpcs = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module act1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:act1\";"
+ " prefix a;"
+ " feature f;"
+ " extension ext;"
+ " container top {"
+ " action test {"
+ " description test;"
+ " grouping grp {}"
+ " if-feature f;"
+ " reference test;"
+ " status current;"
+ " typedef mytype {type int8;}"
+ " a:ext;"
+ " input {"
+ " anydata a1;"
+ " anyxml a2;"
+ " choice ch { leaf x { type empty; } }"
+ " container c;"
+ " grouping grp-in {}"
+ " leaf l {type int8;}"
+ " leaf-list ll {type int8;}"
+ " list li { key k; leaf k {type empty;} }"
+ " must 'true()';"
+ " typedef mytypei {type int8;}"
+ " uses grp-in;"
+ " a:ext;"
+ " }"
+ " output {"
+ " anydata a1;"
+ " anyxml a2;"
+ " choice ch { leaf x { type empty; } }"
+ " container c;"
+ " grouping grp-out {}"
+ " leaf l {type int8;}"
+ " leaf-list ll {type int8;}"
+ " list li { key k; leaf k {type empty;} }"
+ " must 'true()';"
+ " typedef mytypeo {type int8;}"
+ " uses grp-out;"
+ " a:ext;"
+ " }"
+ " }"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid content */
- in.current = "func {config true} ...";
- assert_int_equal(LY_EVALID, parse_action(YCTX, NULL, &rpcs));
- CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"rpc\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)rpcs); rpcs = NULL;
-
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)c);
+ TEST_MOD(UTEST_LYCTX,
+ "module act2 {"
+ " yang-version 1.1;"
+ " namespace \"urn:act2\";"
+ " prefix a;"
+ " container top {"
+ " action func { config true; }"
+ " }"
+ "}",
+ LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"act2\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"action\".", NULL, 1);
}
static void
test_notification(void **state)
{
- struct lysp_node_notif *notifs = NULL;
- struct lysp_node_container *c = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
-
- /* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "func {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_notif(YCTX, NULL, ¬ifs)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)notifs); notifs = NULL;
+ TEST_MOD(UTEST_LYCTX, "module notif1 { yang-version 1.1; namespace \"urn:notif1\"; prefix n; notification ntf { " MEMBER " " VALUE1 "; " MEMBER " " VALUE2 "; } }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"notif1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
- TEST_DUP("description", "text1", "text2");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
#undef TEST_DUP
/* full content */
- in.current = "top;";
- assert_int_equal(LY_SUCCESS, parse_container(YCTX, NULL, (struct lysp_node **)&c));
- in.current = "ntf {anydata a1; anyxml a2; choice ch; container c; description test; grouping grp; if-feature f; leaf l {type int8;}"
- "leaf-list ll {type int8;} list li; must 1; reference test; status current; typedef mytype {type int8;} uses grp; m:ext;}";
- assert_int_equal(LY_SUCCESS, parse_notif(YCTX, (struct lysp_node *)c, ¬ifs));
- assert_non_null(notifs);
- assert_int_equal(LYS_NOTIF, notifs->nodetype);
- assert_string_equal("ntf", notifs->name);
- assert_string_equal("test", notifs->dsc);
- assert_non_null(notifs->exts);
- assert_non_null(notifs->iffeatures);
- assert_string_equal("test", notifs->ref);
- assert_non_null(notifs->groupings);
- assert_non_null(notifs->typedefs);
- assert_non_null(notifs->musts);
- assert_non_null(notifs->child);
- assert_int_equal(LYS_STATUS_CURR, notifs->flags);
-
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- ly_set_erase(&YCTX->grps_nodes, NULL);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)notifs); notifs = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module notif1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:notif1\";"
+ " prefix n;"
+ " feature f;"
+ " extension ext;"
+ " container top {"
+ " notification ntf {"
+ " anydata a1;"
+ " anyxml a2;"
+ " choice ch { leaf x { type empty; } }"
+ " container c;"
+ " description test;"
+ " grouping grp {}"
+ " if-feature f;"
+ " leaf l {type int8;}"
+ " leaf-list ll {type int8;}"
+ " list li { key k; leaf k {type empty;} }"
+ " must 'true()';"
+ " reference test;"
+ " status current;"
+ " typedef mytype {type int8;}"
+ " uses grp;"
+ " n:ext;"
+ " }"
+ " }"
+ "}",
+ LY_SUCCESS);
/* invalid content */
- in.current = "ntf {config true} ...";
- assert_int_equal(LY_EVALID, parse_notif(YCTX, NULL, ¬ifs));
+ TEST_MOD(UTEST_LYCTX,
+ "module notif2 {"
+ " yang-version 1.1;"
+ " namespace \"urn:notif2\";"
+ " prefix n;"
+ " notification ntf { config true; }" /* Notifications cannot have config true */
+ "}",
+ LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"notif2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"notification\".", NULL, 1);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)notifs); notifs = NULL;
-
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)c);
}
static void
test_uses(void **state)
{
- struct lysp_node_uses *u = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_uses(YCTX, NULL, (struct lysp_node**)&u)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node*)u); u = NULL;
+ TEST_MOD(UTEST_LYCTX, "module uses1 { yang-version 1.1; namespace \"urn:uses1\"; prefix u; grouping g; container c { uses g { " MEMBER " " VALUE1 "; " MEMBER " " VALUE2 "; } } }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"uses1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
- TEST_DUP("description", "text1", "text2");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content */
- in.current = "grpref {augment some/node;description test;if-feature f;reference test;refine some/other/node;status current;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_uses(YCTX, NULL, (struct lysp_node **)&u));
- CHECK_LYSP_NODE(u, "test", 1, LYS_STATUS_CURR, 1, "grpref", 0, LYS_USES, 0, "test", 1);
- assert_non_null(u->augments);
- assert_non_null(u->refines);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)u); u = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module uses1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:uses1\";"
+ " prefix u;"
+ " feature f;"
+ " extension ext;"
+ " "
+ " /* We MUST build the tree inside the grouping so augment/refine can find their targets! */"
+ " grouping grpref {"
+ " container some {"
+ " container node;"
+ " container other {"
+ " leaf node { type string; }"
+ " }"
+ " }"
+ " }"
+ " "
+ " container top {"
+ " uses grpref {"
+ " augment \"some/node\" { leaf new-leaf { type empty; } }"
+ " description test;"
+ " if-feature f;"
+ " reference test;"
+ " refine \"some/other/node\" { description \"refined\"; }"
+ " status current;"
+ " when 'true()';"
+ " u:ext;"
+ " }"
+ " }"
+ "}",
+ LY_SUCCESS);
}
static void
test_augment(void **state)
{
- struct lysp_node_augment *a = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_augment(YCTX, NULL, &a)); \
- CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1); \
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)a); a = NULL;
+ TEST_MOD(UTEST_LYCTX, "module aug1 { yang-version 1.1; namespace \"urn:aug1\"; prefix a; container target { container nodeid; } augment \"/a:target/a:nodeid\" { " MEMBER " " VALUE1 "; " MEMBER " " VALUE2 "; } }", LY_EVALID);\
+ CHECK_LOG_CTX("Parsing module \"aug1\" failed.", NULL, 0);\
+ CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", NULL, 1);
- TEST_DUP("description", "text1", "text2");
- TEST_DUP("reference", "1", "2");
+ TEST_DUP("description", "\"text1\"", "\"text2\"");
+ TEST_DUP("reference", "\"1\"", "\"2\"");
TEST_DUP("status", "current", "obsolete");
- TEST_DUP("when", "true", "false");
+ TEST_DUP("when", "'true()'", "'false()'");
#undef TEST_DUP
/* full content */
- in.current = "/target/nodeid {action x; anydata any;anyxml anyxml; case cs; choice ch;container c;description test;if-feature f;leaf l {type string;}"
- "leaf-list ll {type string;} list li;notification not;reference test;status current;uses g;when true;m:ext;} ...";
- assert_int_equal(LY_SUCCESS, parse_augment(YCTX, NULL, &a));
- assert_non_null(a);
- assert_int_equal(LYS_AUGMENT, a->nodetype);
- assert_string_equal("/target/nodeid", a->nodeid);
- assert_string_equal("test", a->dsc);
- assert_non_null(a->exts);
- assert_non_null(a->iffeatures);
- assert_string_equal("test", a->ref);
- assert_non_null(a->when);
- assert_null(a->parent);
- assert_int_equal(LYS_STATUS_CURR, a->flags);
- lysp_node_free(PARSER_CTX(YCTX), (struct lysp_node *)a); a = NULL;
+ TEST_MOD(UTEST_LYCTX,
+ "module aug1 {"
+ " yang-version 1.1;"
+ " namespace \"urn:aug1\";"
+ " prefix a;"
+ " feature f;"
+ " extension ext;"
+ " grouping g;"
+ " "
+ " container target {"
+ " container nodeid;"
+ " choice ch;"
+ " }"
+ " "
+ " /* Augmenting a container */"
+ " augment \"/a:target/a:nodeid\" {"
+ " action x;"
+ " anydata any;"
+ " anyxml anyxml;"
+ " choice ch { leaf ch-l { type empty; } }"
+ " container c;"
+ " description test;"
+ " if-feature f;"
+ " leaf l {type string;}"
+ " leaf-list ll {type string;}"
+ " list li { key k; leaf k {type empty;} }"
+ " notification not;"
+ " reference test;"
+ " status current;"
+ " uses g;"
+ " when 'true()';"
+ " a:ext;"
+ " }"
+ " "
+ " augment \"/a:target/a:ch\" {"
+ " case cs { leaf cs-l { type empty; } }"
+ " }"
+ "}",
+ LY_SUCCESS);
}
static void
test_when(void **state)
{
- struct lysp_when *w = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
-
- in.current = "l { description text1;description text2;} ...";
- assert_int_equal(LY_EVALID, parse_when(YCTX, &w));
- assert_null(w);
+ TEST_MOD(UTEST_LYCTX, "module when1 { yang-version 1.1; namespace \"urn:when1\"; prefix w; leaf l { type empty; when 'true()' { description text1; description text2; } } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"when1\" failed.", NULL, 0);
CHECK_LOG_CTX("Duplicate keyword \"description\".", NULL, 1);
- in.current = "l { reference 1;reference 2;} ...";
- assert_int_equal(LY_EVALID, parse_when(YCTX, &w));
- assert_null(w);
+ TEST_MOD(UTEST_LYCTX, "module when1 { yang-version 1.1; namespace \"urn:when1\"; prefix w; leaf l { type empty; when 'true()' { reference 1; reference 2; } } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"when1\" failed.", NULL, 0);
CHECK_LOG_CTX("Duplicate keyword \"reference\".", NULL, 1);
}
static void
test_value(void **state)
{
- struct lysp_type_enum enm;
-
- in.current = "-0;";
- memset(&enm, 0, sizeof enm);
- assert_int_equal(parse_type_enum_value_pos(YCTX, LY_STMT_VALUE, &enm), LY_SUCCESS);
+ TEST_MOD(UTEST_LYCTX, "module val1 { yang-version 1.1; namespace \"urn:val1\"; prefix v; leaf l { type enumeration { enum a { value -0; } } } }", LY_SUCCESS);
- in.current = "-0;";
- memset(&enm, 0, sizeof enm);
- assert_int_equal(parse_type_enum_value_pos(YCTX, LY_STMT_POSITION, &enm), LY_EVALID);
+ TEST_MOD(UTEST_LYCTX, "module val2 { yang-version 1.1; namespace \"urn:val2\"; prefix v; leaf l { type bits { bit a { position -0; } } } }", LY_EVALID);
+ CHECK_LOG_CTX("Parsing module \"val2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-0\" of \"position\".", NULL, 1);
}
@@ -1714,30 +1490,30 @@ int
main(void)
{
const struct CMUnitTest tests[] = {
- UTEST(test_helpers, setup, teardown),
- UTEST(test_comments, setup, teardown),
- UTEST(test_arg, setup, teardown),
- UTEST(test_stmts, setup, teardown),
- UTEST(test_minmax, setup, teardown),
- UTEST(test_valid_module, setup, teardown),
- UTEST(test_module, setup, teardown),
- UTEST(test_deviation, setup, teardown),
- UTEST(test_deviate, setup, teardown),
- UTEST(test_container, setup, teardown),
- UTEST(test_leaf, setup, teardown),
- UTEST(test_leaflist, setup, teardown),
- UTEST(test_list, setup, teardown),
- UTEST(test_choice, setup, teardown),
- UTEST(test_case, setup, teardown),
- UTEST(test_anydata, setup, teardown),
- UTEST(test_anyxml, setup, teardown),
- UTEST(test_action, setup, teardown),
- UTEST(test_notification, setup, teardown),
- UTEST(test_grouping, setup, teardown),
- UTEST(test_uses, setup, teardown),
- UTEST(test_augment, setup, teardown),
- UTEST(test_when, setup, teardown),
- UTEST(test_value, setup, teardown),
+ UTEST(test_helpers),
+ UTEST(test_comments),
+ UTEST(test_arg),
+ UTEST(test_stmts),
+ UTEST(test_minmax),
+ UTEST(test_valid_module),
+ UTEST(test_module),
+ UTEST(test_deviation),
+ UTEST(test_deviate),
+ UTEST(test_container),
+ UTEST(test_leaf),
+ UTEST(test_leaflist),
+ UTEST(test_list),
+ UTEST(test_choice),
+ UTEST(test_case),
+ UTEST(test_anydata),
+ UTEST(test_anyxml),
+ UTEST(test_action),
+ UTEST(test_notification),
+ UTEST(test_grouping),
+ UTEST(test_uses),
+ UTEST(test_augment),
+ UTEST(test_when),
+ UTEST(test_value),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/utests/schema/test_yin.c b/tests/utests/schema/test_yin.c
index 50eab90346..f1b7cda397 100644
--- a/tests/utests/schema/test_yin.c
+++ b/tests/utests/schema/test_yin.c
@@ -20,382 +20,145 @@
#include
#include "in.h"
-#include "ly_common.h"
-#include "parser_internal.h"
-#include "schema_compile.h"
#include "tree.h"
#include "tree_edit.h"
#include "tree_schema.h"
-#include "tree_schema_internal.h"
-#include "xml.h"
-#include "xpath.h"
-
-/* copied from parser_yin.c */
-enum yin_argument {
- YIN_ARG_UNKNOWN = 0, /**< parsed argument can not be matched with any supported yin argument keyword */
- YIN_ARG_NAME, /**< argument name */
- YIN_ARG_TARGET_NODE, /**< argument target-node */
- YIN_ARG_MODULE, /**< argument module */
- YIN_ARG_VALUE, /**< argument value */
- YIN_ARG_TEXT, /**< argument text */
- YIN_ARG_CONDITION, /**< argument condition */
- YIN_ARG_URI, /**< argument uri */
- YIN_ARG_DATE, /**< argument data */
- YIN_ARG_TAG, /**< argument tag */
- YIN_ARG_NONE /**< empty (special value) */
-};
-
-struct yin_subelement {
- enum ly_stmt type; /**< type of keyword */
- void *dest; /**< meta infromation passed to responsible function (mostly information about where parsed subelement should be stored) */
- uint16_t flags; /**< describes constraints of subelement can be set to YIN_SUBELEM_MANDATORY, YIN_SUBELEM_UNIQUE, YIN_SUBELEM_FIRST, YIN_SUBELEM_VER2, and YIN_SUBELEM_DEFAULT_TEXT */
-};
-
-struct import_meta {
- const char *prefix; /**< module prefix. */
- struct lysp_import **imports; /**< imports to add to. */
-};
-
-struct yin_argument_meta {
- uint16_t *flags; /**< Argument flags */
- const char **argument; /**< Argument value */
-};
-
-struct tree_node_meta {
- struct lysp_node *parent; /**< parent node */
- struct lysp_node **nodes; /**< linked list of siblings */
-};
-
-struct include_meta {
- const char *name; /**< Module/submodule name. */
- struct lysp_include **includes; /**< [Sized array](@ref sizedarrays) of parsed includes to add to. */
-};
-
-struct inout_meta {
- struct lysp_node *parent; /**< Parent node. */
- struct lysp_node_action_inout *inout_p; /**< inout_p Input/output pointer to write to. */
-};
-
-struct minmax_dev_meta {
- uint32_t *lim; /**< min/max value to write to. */
- uint16_t *flags; /**< min/max flags to write to. */
- struct lysp_ext_instance **exts; /**< extension instances to add to. */
-};
-
-#define YIN_SUBELEM_MANDATORY 0x01
-#define YIN_SUBELEM_UNIQUE 0x02
-#define YIN_SUBELEM_FIRST 0x04
-#define YIN_SUBELEM_VER2 0x08
-
-#define YIN_SUBELEM_PARSED 0x80
-
-/* prototypes of static functions */
-enum yin_argument yin_match_argument_name(const char *name, size_t len);
-
-LY_ERR yin_parse_content(struct lysp_yin_ctx *ctx, struct yin_subelement *subelem_info, size_t subelem_info_size,
- const void *parent, enum ly_stmt parent_stmt, const char **text_content, struct lysp_ext_instance **exts);
-LY_ERR yin_validate_value(struct lysp_yin_ctx *ctx, enum yang_arg val_type);
-enum ly_stmt yin_match_keyword(struct lysp_yin_ctx *ctx, const char *name, size_t name_len,
- const char *prefix, size_t prefix_len, enum ly_stmt parrent);
-
-LY_ERR yin_parse_extension_instance(struct lysp_yin_ctx *ctx, const void *parent, enum ly_stmt parent_stmt,
- LY_ARRAY_COUNT_TYPE parent_stmt_index, struct lysp_ext_instance **exts);
-LY_ERR yin_parse_element_generic(struct lysp_yin_ctx *ctx, enum ly_stmt parent, struct lysp_stmt **element);
-LY_ERR yin_parse_mod(struct lysp_yin_ctx *ctx, struct lysp_module *mod);
-LY_ERR yin_parse_submod(struct lysp_yin_ctx *ctx, struct lysp_submodule *submod);
-
-/* wrapping element used for mocking has nothing to do with real module structure */
-#define ELEMENT_WRAPPER_START ""
-#define ELEMENT_WRAPPER_END ""
-
-#define TEST_1_CHECK_LYSP_EXT_INSTANCE(NODE, INSUBSTMT)\
- CHECK_LYSP_EXT_INSTANCE((NODE), NULL, 1, INSUBSTMT, 0, "myext:c-define", LY_VALUE_XML)
-
-struct lysp_yin_ctx *YCTX;
-
-static int
-setup_ctx(void **state)
-{
- struct lysp_module *pmod;
-
- /* allocate parser context */
- YCTX = calloc(1, sizeof(*YCTX));
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
- YCTX->format = LYS_IN_YIN;
- ly_set_new(&YCTX->parsed_mods);
-
- /* allocate new parsed module */
- pmod = calloc(1, sizeof *pmod);
- ly_set_add(YCTX->parsed_mods, pmod, 1, NULL);
-
- /* allocate new module */
- pmod->mod = calloc(1, sizeof *pmod->mod);
- pmod->mod->ctx = UTEST_LYCTX;
- pmod->mod->parsed = pmod;
-
- return 0;
-}
-
-static int
-setup(void **state)
-{
- UTEST_SETUP;
-
- setup_ctx(state);
- return 0;
-}
-
-static int
-teardown_ctx(void **state)
-{
- lys_module_free(UTEST_LYCTX, PARSER_CUR_PMOD(YCTX)->mod, 0);
- lysp_yin_ctx_free(YCTX);
- YCTX = NULL;
-
- return 0;
-}
-
-static int
-teardown(void **state)
-{
- teardown_ctx(state);
-
- UTEST_TEARDOWN;
-
- return 0;
-}
-
-#define RESET_STATE \
- ly_in_free(UTEST_IN, 0); \
- UTEST_IN = NULL; \
- teardown_ctx(state); \
- setup_ctx(state)
+#define TEST_1_CHECK_LYSP_EXT_INSTANCE(NODE, INSUBSTMT, ARGUMENT)\
+ CHECK_LYSP_EXT_INSTANCE((NODE), (ARGUMENT), 1, INSUBSTMT, 0, "myext:c-define", LY_VALUE_XML)
static void
test_yin_match_keyword(void **state)
{
- const char *prefix;
- size_t prefix_len;
-
- /* create mock yin namespace in xml context */
- ly_in_new_memory("", &UTEST_IN);
- lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx);
- prefix = YCTX->xmlctx->prefix;
- prefix_len = YCTX->xmlctx->prefix_len;
-
- assert_int_equal(yin_match_keyword(YCTX, "anydatax", strlen("anydatax"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_NONE);
- assert_int_equal(yin_match_keyword(YCTX, "asdasd", strlen("asdasd"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_NONE);
- assert_int_equal(yin_match_keyword(YCTX, "", 0, prefix, prefix_len, LY_STMT_NONE), LY_STMT_NONE);
- assert_int_equal(yin_match_keyword(YCTX, "anydata", strlen("anydata"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ANYDATA);
- assert_int_equal(yin_match_keyword(YCTX, "anyxml", strlen("anyxml"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ANYXML);
- assert_int_equal(yin_match_keyword(YCTX, "argument", strlen("argument"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ARGUMENT);
- assert_int_equal(yin_match_keyword(YCTX, "augment", strlen("augment"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_AUGMENT);
- assert_int_equal(yin_match_keyword(YCTX, "base", strlen("base"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_BASE);
- assert_int_equal(yin_match_keyword(YCTX, "belongs-to", strlen("belongs-to"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_BELONGS_TO);
- assert_int_equal(yin_match_keyword(YCTX, "bit", strlen("bit"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_BIT);
- assert_int_equal(yin_match_keyword(YCTX, "case", strlen("case"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_CASE);
- assert_int_equal(yin_match_keyword(YCTX, "choice", strlen("choice"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_CHOICE);
- assert_int_equal(yin_match_keyword(YCTX, "config", strlen("config"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_CONFIG);
- assert_int_equal(yin_match_keyword(YCTX, "contact", strlen("contact"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_CONTACT);
- assert_int_equal(yin_match_keyword(YCTX, "container", strlen("container"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_CONTAINER);
- assert_int_equal(yin_match_keyword(YCTX, "default", strlen("default"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_DEFAULT);
- assert_int_equal(yin_match_keyword(YCTX, "description", strlen("description"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_DESCRIPTION);
- assert_int_equal(yin_match_keyword(YCTX, "deviate", strlen("deviate"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_DEVIATE);
- assert_int_equal(yin_match_keyword(YCTX, "deviation", strlen("deviation"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_DEVIATION);
- assert_int_equal(yin_match_keyword(YCTX, "enum", strlen("enum"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ENUM);
- assert_int_equal(yin_match_keyword(YCTX, "error-app-tag", strlen("error-app-tag"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ERROR_APP_TAG);
- assert_int_equal(yin_match_keyword(YCTX, "error-message", strlen("error-message"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ERROR_MESSAGE);
- assert_int_equal(yin_match_keyword(YCTX, "extension", strlen("extension"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_EXTENSION);
- assert_int_equal(yin_match_keyword(YCTX, "feature", strlen("feature"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_FEATURE);
- assert_int_equal(yin_match_keyword(YCTX, "fraction-digits", strlen("fraction-digits"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_FRACTION_DIGITS);
- assert_int_equal(yin_match_keyword(YCTX, "grouping", strlen("grouping"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_GROUPING);
- assert_int_equal(yin_match_keyword(YCTX, "identity", strlen("identity"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_IDENTITY);
- assert_int_equal(yin_match_keyword(YCTX, "if-feature", strlen("if-feature"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_IF_FEATURE);
- assert_int_equal(yin_match_keyword(YCTX, "import", strlen("import"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_IMPORT);
- assert_int_equal(yin_match_keyword(YCTX, "include", strlen("include"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_INCLUDE);
- assert_int_equal(yin_match_keyword(YCTX, "input", strlen("input"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_INPUT);
- assert_int_equal(yin_match_keyword(YCTX, "key", strlen("key"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_KEY);
- assert_int_equal(yin_match_keyword(YCTX, "leaf", strlen("leaf"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_LEAF);
- assert_int_equal(yin_match_keyword(YCTX, "leaf-list", strlen("leaf-list"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_LEAF_LIST);
- assert_int_equal(yin_match_keyword(YCTX, "length", strlen("length"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_LENGTH);
- assert_int_equal(yin_match_keyword(YCTX, "list", strlen("list"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_LIST);
- assert_int_equal(yin_match_keyword(YCTX, "mandatory", strlen("mandatory"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_MANDATORY);
- assert_int_equal(yin_match_keyword(YCTX, "max-elements", strlen("max-elements"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_MAX_ELEMENTS);
- assert_int_equal(yin_match_keyword(YCTX, "min-elements", strlen("min-elements"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_MIN_ELEMENTS);
- assert_int_equal(yin_match_keyword(YCTX, "modifier", strlen("modifier"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_MODIFIER);
- assert_int_equal(yin_match_keyword(YCTX, "module", strlen("module"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_MODULE);
- assert_int_equal(yin_match_keyword(YCTX, "must", strlen("must"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_MUST);
- assert_int_equal(yin_match_keyword(YCTX, "namespace", strlen("namespace"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_NAMESPACE);
- assert_int_equal(yin_match_keyword(YCTX, "notification", strlen("notification"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_NOTIFICATION);
- assert_int_equal(yin_match_keyword(YCTX, "ordered-by", strlen("ordered-by"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ORDERED_BY);
- assert_int_equal(yin_match_keyword(YCTX, "organization", strlen("organization"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_ORGANIZATION);
- assert_int_equal(yin_match_keyword(YCTX, "output", strlen("output"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_OUTPUT);
- assert_int_equal(yin_match_keyword(YCTX, "path", strlen("path"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_PATH);
- assert_int_equal(yin_match_keyword(YCTX, "pattern", strlen("pattern"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_PATTERN);
- assert_int_equal(yin_match_keyword(YCTX, "position", strlen("position"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_POSITION);
- assert_int_equal(yin_match_keyword(YCTX, "prefix", strlen("prefix"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_PREFIX);
- assert_int_equal(yin_match_keyword(YCTX, "presence", strlen("presence"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_PRESENCE);
- assert_int_equal(yin_match_keyword(YCTX, "range", strlen("range"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_RANGE);
- assert_int_equal(yin_match_keyword(YCTX, "reference", strlen("reference"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_REFERENCE);
- assert_int_equal(yin_match_keyword(YCTX, "refine", strlen("refine"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_REFINE);
- assert_int_equal(yin_match_keyword(YCTX, "require-instance", strlen("require-instance"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_REQUIRE_INSTANCE);
- assert_int_equal(yin_match_keyword(YCTX, "revision", strlen("revision"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_REVISION);
- assert_int_equal(yin_match_keyword(YCTX, "revision-date", strlen("revision-date"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_REVISION_DATE);
- assert_int_equal(yin_match_keyword(YCTX, "rpc", strlen("rpc"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_RPC);
- assert_int_equal(yin_match_keyword(YCTX, "status", strlen("status"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_STATUS);
- assert_int_equal(yin_match_keyword(YCTX, "submodule", strlen("submodule"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_SUBMODULE);
- assert_int_equal(yin_match_keyword(YCTX, "type", strlen("type"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_TYPE);
- assert_int_equal(yin_match_keyword(YCTX, "typedef", strlen("typedef"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_TYPEDEF);
- assert_int_equal(yin_match_keyword(YCTX, "unique", strlen("unique"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_UNIQUE);
- assert_int_equal(yin_match_keyword(YCTX, "units", strlen("units"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_UNITS);
- assert_int_equal(yin_match_keyword(YCTX, "uses", strlen("uses"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_USES);
- assert_int_equal(yin_match_keyword(YCTX, "value", strlen("value"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_VALUE);
- assert_int_equal(yin_match_keyword(YCTX, "when", strlen("when"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_WHEN);
- assert_int_equal(yin_match_keyword(YCTX, "yang-version", strlen("yang-version"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_YANG_VERSION);
- assert_int_equal(yin_match_keyword(YCTX, "yin-element", strlen("yin-element"), prefix, prefix_len, LY_STMT_NONE), LY_STMT_YIN_ELEMENT);
-}
+ const char *yin_data;
-static void
-test_yin_match_argument_name(void **UNUSED(state))
-{
- assert_int_equal(yin_match_argument_name("", 5), YIN_ARG_UNKNOWN);
- assert_int_equal(yin_match_argument_name("qwertyasd", 5), YIN_ARG_UNKNOWN);
- assert_int_equal(yin_match_argument_name("conditionasd", 8), YIN_ARG_UNKNOWN);
- assert_int_equal(yin_match_argument_name("condition", 9), YIN_ARG_CONDITION);
- assert_int_equal(yin_match_argument_name("date", 4), YIN_ARG_DATE);
- assert_int_equal(yin_match_argument_name("module", 6), YIN_ARG_MODULE);
- assert_int_equal(yin_match_argument_name("name", 4), YIN_ARG_NAME);
- assert_int_equal(yin_match_argument_name("tag", 3), YIN_ARG_TAG);
- assert_int_equal(yin_match_argument_name("target-node", 11), YIN_ARG_TARGET_NODE);
- assert_int_equal(yin_match_argument_name("text", 4), YIN_ARG_TEXT);
- assert_int_equal(yin_match_argument_name("uri", 3), YIN_ARG_URI);
- assert_int_equal(yin_match_argument_name("value", 5), YIN_ARG_VALUE);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Unexpected sub-element \"anydatax\" of \"module\" element.", NULL, 1);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Unexpected sub-element \"asdasd\" of \"module\" element.", NULL, 1);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " >"
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Identifier \">\" starts with an invalid character.", NULL, 1);
}
static void
test_yin_parse_content(void **state)
{
- LY_ERR ret = LY_SUCCESS;
- const char *data =
- "\n"
- " totally amazing extension\n"
- " \n"
- " \n"
- " desc\n"
- " ref\n"
- " \n"
- " \n"
- " wsefsdf\n"
- " \n"
- " \n"
- " when_ref\n"
- " when_desc\n"
- " \n"
- " \n"
- " \n"
- " error-msg\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- "";
- struct lysp_ext_instance *exts = NULL;
- const char *value;
-
- /* test unique subelem */
- const char *prefix_value;
- struct yin_subelement subelems2[2] = {{LY_STMT_PREFIX, &prefix_value, YIN_SUBELEM_UNIQUE},
- {LY_STMT_ARG_TEXT, &value, YIN_SUBELEM_UNIQUE}};
-
- data = ELEMENT_WRAPPER_START
- ""
- "wsefsdf"
- "wsefsdf"
- ELEMENT_WRAPPER_END;
- ly_in_new_memory(data, &UTEST_IN);
- lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx);
- lyxml_ctx_next(YCTX->xmlctx);
-
- ret = yin_parse_content(YCTX, subelems2, 2, NULL, LY_STMT_STATUS, NULL, &exts);
- assert_int_equal(ret, LY_EVALID);
- CHECK_LOG_CTX("Redefinition of \"text\" sub-element in \"status\" element.", NULL, 1);
- lysdict_remove(UTEST_LYCTX, prefix_value);
- lysdict_remove(UTEST_LYCTX, value);
- RESET_STATE;
-
- /* test first subelem */
- data = ELEMENT_WRAPPER_START
- ""
- "wsefsdf"
- "wsefsdf"
- ELEMENT_WRAPPER_END;
- struct yin_subelement subelems3[2] = {{LY_STMT_PREFIX, &prefix_value, YIN_SUBELEM_UNIQUE},
- {LY_STMT_ARG_TEXT, &value, YIN_SUBELEM_FIRST}};
-
- ly_in_new_memory(data, &UTEST_IN);
- lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx);
- lyxml_ctx_next(YCTX->xmlctx);
-
- ret = yin_parse_content(YCTX, subelems3, 2, NULL, LY_STMT_STATUS, NULL, &exts);
- assert_int_equal(ret, LY_EVALID);
- CHECK_LOG_CTX("Sub-element \"text\" of \"status\" element must be defined as it's first sub-element.", NULL, 1);
- lysdict_remove(UTEST_LYCTX, prefix_value);
- RESET_STATE;
-
- /* test mandatory subelem */
- data = ELEMENT_WRAPPER_START ELEMENT_WRAPPER_END;
- struct yin_subelement subelems4[1] = {{LY_STMT_PREFIX, &prefix_value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE}};
-
- ly_in_new_memory(data, &UTEST_IN);
- lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx);
- lyxml_ctx_next(YCTX->xmlctx);
-
- ret = yin_parse_content(YCTX, subelems4, 1, NULL, LY_STMT_STATUS, NULL, &exts);
- assert_int_equal(ret, LY_EVALID);
- CHECK_LOG_CTX("Missing mandatory sub-element \"prefix\" of \"status\" element.", NULL, 1);
+ const char *yin_data;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " First text"
+ " Second text (invalid duplication)"
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Redefinition of \"text\" sub-element in \"description\" element.", NULL, 1);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " Desc"
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid order of module's sub-elements \"description\" can't appear after \"extension\".", NULL, 1);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"test\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Missing mandatory sub-element \"text\" of \"description\" element.", NULL, 1);
+
}
static void
test_validate_value(void **state)
{
- const char *data = ELEMENT_WRAPPER_START ELEMENT_WRAPPER_END;
-
- /* create some XML context */
- ly_in_new_memory(data, &UTEST_IN);
- lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx);
- YCTX->xmlctx->status = LYXML_ELEM_CONTENT;
- YCTX->xmlctx->dynamic = 0;
+ char buffer[512];
+ const char *yin_ident =
+ ""
+ " "
+ " "
+ " "
+ "";
+ const char *yin_str_empty =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
+ const char *yin_pref =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- YCTX->xmlctx->value = "#invalid";
- YCTX->xmlctx->value_len = 8;
- assert_int_equal(yin_validate_value(YCTX, Y_IDENTIF_ARG), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_ident, "#invalid");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Invalid identifier first character '#' (0x0023).", NULL, 1);
- YCTX->xmlctx->value = "";
- YCTX->xmlctx->value_len = 0;
- assert_int_equal(yin_validate_value(YCTX, Y_STR_ARG), LY_SUCCESS);
-
- YCTX->xmlctx->value = "pre:b";
- YCTX->xmlctx->value_len = 5;
- assert_int_equal(yin_validate_value(YCTX, Y_IDENTIF_ARG), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_ident, "pre:b");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", NULL, 1);
- assert_int_equal(yin_validate_value(YCTX, Y_PREF_IDENTIF_ARG), LY_SUCCESS);
- YCTX->xmlctx->value = "pre:pre:b";
- YCTX->xmlctx->value_len = 9;
- assert_int_equal(yin_validate_value(YCTX, Y_PREF_IDENTIF_ARG), LY_EVALID);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_str_empty, LYS_IN_YIN, NULL));
+
+ snprintf(buffer, sizeof(buffer), yin_pref, "pre:pre:b");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"t3\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", NULL, 1);
+
+ snprintf(buffer, sizeof(buffer), yin_pref, "pre:b");
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
}
static void
@@ -1167,186 +930,142 @@ test_print_submodule(void **state)
ly_out_free(out, NULL, 1);
}
-/* helper function to simplify unit test of each element using parse_content function */
-LY_ERR
-test_element_helper(void **state, const char *data, void *dest, const char **text, struct lysp_ext_instance **exts)
-{
- const char *name, *prefix;
- size_t name_len, prefix_len;
- LY_ERR ret = LY_SUCCESS;
- struct yin_subelement subelems[71] = {
- {LY_STMT_ACTION, dest, 0},
- {LY_STMT_ANYDATA, dest, 0},
- {LY_STMT_ANYXML, dest, 0},
- {LY_STMT_ARGUMENT, dest, 0},
- {LY_STMT_AUGMENT, dest, 0},
- {LY_STMT_BASE, dest, 0},
- {LY_STMT_BELONGS_TO, dest, 0},
- {LY_STMT_BIT, dest, 0},
- {LY_STMT_CASE, dest, 0},
- {LY_STMT_CHOICE, dest, 0},
- {LY_STMT_CONFIG, dest, 0},
- {LY_STMT_CONTACT, dest, 0},
- {LY_STMT_CONTAINER, dest, 0},
- {LY_STMT_DEFAULT, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_DESCRIPTION, dest, 0},
- {LY_STMT_DEVIATE, dest, 0},
- {LY_STMT_DEVIATION, dest, 0},
- {LY_STMT_ENUM, dest, 0},
- {LY_STMT_ERROR_APP_TAG, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_ERROR_MESSAGE, dest, 0},
- {LY_STMT_EXTENSION, dest, 0},
- {LY_STMT_FEATURE, dest, 0},
- {LY_STMT_FRACTION_DIGITS, dest, 0},
- {LY_STMT_GROUPING, dest, 0},
- {LY_STMT_IDENTITY, dest, 0},
- {LY_STMT_IF_FEATURE, dest, 0},
- {LY_STMT_IMPORT, dest, 0},
- {LY_STMT_INCLUDE, dest, 0},
- {LY_STMT_INPUT, dest, 0},
- {LY_STMT_KEY, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_LEAF, dest, 0},
- {LY_STMT_LEAF_LIST, dest, 0},
- {LY_STMT_LENGTH, dest, 0},
- {LY_STMT_LIST, dest, 0},
- {LY_STMT_MANDATORY, dest, 0},
- {LY_STMT_MAX_ELEMENTS, dest, 0},
- {LY_STMT_MIN_ELEMENTS, dest, 0},
- {LY_STMT_MODIFIER, dest, 0},
- {LY_STMT_MODULE, dest, 0},
- {LY_STMT_MUST, dest, 0},
- {LY_STMT_NAMESPACE, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_NOTIFICATION, dest, 0},
- {LY_STMT_ORDERED_BY, dest, 0},
- {LY_STMT_ORGANIZATION, dest, 0},
- {LY_STMT_OUTPUT, dest, 0},
- {LY_STMT_PATH, dest, 0},
- {LY_STMT_PATTERN, dest, 0},
- {LY_STMT_POSITION, dest, 0},
- {LY_STMT_PREFIX, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_PRESENCE, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_RANGE, dest, 0},
- {LY_STMT_REFERENCE, dest, 0},
- {LY_STMT_REFINE, dest, 0},
- {LY_STMT_REQUIRE_INSTANCE, dest, 0},
- {LY_STMT_REVISION, dest, 0},
- {LY_STMT_REVISION_DATE, dest, 0},
- {LY_STMT_RPC, dest, 0},
- {LY_STMT_STATUS, dest, 0},
- {LY_STMT_SUBMODULE, dest, 0},
- {LY_STMT_TYPE, dest, 0},
- {LY_STMT_TYPEDEF, dest, 0},
- {LY_STMT_UNIQUE, dest, 0},
- {LY_STMT_UNITS, dest, YIN_SUBELEM_UNIQUE},
- {LY_STMT_USES, dest, 0},
- {LY_STMT_VALUE, dest, 0},
- {LY_STMT_WHEN, dest, 0},
- {LY_STMT_YANG_VERSION, dest, 0},
- {LY_STMT_YIN_ELEMENT, dest, 0},
- {LY_STMT_EXTENSION_INSTANCE, dest, 0},
- {LY_STMT_ARG_TEXT, dest, 0},
- {LY_STMT_ARG_VALUE, dest, 0}
- };
-
- YCTX->main_ctx = (struct lysp_ctx *)YCTX;
- ly_in_new_memory(data, &UTEST_IN);
- lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx);
- prefix = YCTX->xmlctx->prefix;
- prefix_len = YCTX->xmlctx->prefix_len;
- name = YCTX->xmlctx->name;
- name_len = YCTX->xmlctx->name_len;
- lyxml_ctx_next(YCTX->xmlctx);
-
- ret = yin_parse_content(YCTX, subelems, 71, NULL,
- yin_match_keyword(YCTX, name, name_len, prefix, prefix_len, LY_STMT_NONE), text, exts);
-
- /* free parser and input */
- lyxml_ctx_free(YCTX->xmlctx);
- YCTX->xmlctx = NULL;
- ly_in_free(UTEST_IN, 0);
- UTEST_IN = NULL;
- return ret;
-}
-
-#define EXT_SUBELEM ""
+#define EXT_SUBELEM ""
static void
test_enum_elem(void **state)
{
- struct lysp_type type = {0};
- const char *data;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " desc...\n"
- " ref...\n"
- " " EXT_SUBELEM "\n"
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ struct lysp_type *type;
uint16_t flags = LYS_STATUS_DEPRC | LYS_SET_VALUE;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc..."
+ " ref..."
+ EXT_SUBELEM
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- CHECK_LYSP_TYPE_ENUM(type.enums, "desc...", 1, flags, 1, "enum-name", "ref...", 55);
- assert_string_equal(type.enums->iffeatures[0].str, "feature");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(type.enums->exts, LY_STMT_ENUM);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof type);
-
- data = ELEMENT_WRAPPER_START
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- assert_string_equal(type.enums->name, "enum-name");
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof type);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_non_null(mod);
+ assert_non_null(mod->parsed);
+ assert_non_null(mod->parsed->data);
+ assert_int_equal(LYS_LEAF, mod->parsed->data->nodetype);
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ CHECK_LYSP_TYPE_ENUM(type->enums, "desc...", 1, flags, 1, "enum-name", "ref...", 55);
+ assert_string_equal(type->enums->iffeatures[0].str, "feature");
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(type->enums->exts, LY_STMT_ENUM, "MY_MTU");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ assert_string_equal(leaf->type.enums[0].name, "enum-name");
}
static void
test_bit_elem(void **state)
{
- struct lysp_type type = {0};
- const char *data;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " desc...\n"
- " ref...\n"
- EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ struct lysp_type *type;
uint16_t flags = LYS_STATUS_DEPRC | LYS_SET_VALUE;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc..."
+ " ref..."
+ EXT_SUBELEM
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- CHECK_LYSP_TYPE_ENUM(type.bits, "desc...", 1, flags, 1, "bit-name", "ref...", 55);
- assert_string_equal(type.bits->iffeatures[0].str, "feature");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(type.bits->exts, LY_STMT_BIT);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof type);
-
- data = ELEMENT_WRAPPER_START
- " "
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_TYPE_ENUM(type.bits, NULL, 0, 0, 0, "bit-name", NULL, 0);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof type);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_non_null(mod);
+ assert_non_null(mod->parsed);
+ assert_non_null(mod->parsed->data);
+ assert_int_equal(LYS_LEAF, mod->parsed->data->nodetype);
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ CHECK_LYSP_TYPE_ENUM(type->bits, "desc...", 1, flags, 1, "bit-name", "ref...", 55);
+ assert_string_equal(type->bits->iffeatures[0].str, "feature");
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(type->bits->exts, LY_STMT_BIT, "MY_MTU");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ CHECK_LYSP_TYPE_ENUM(leaf->type.bits, NULL, 0, 0, 0, "bit-name", NULL, 0);
}
static void
test_status_elem(void **state)
{
- const char *data;
- uint16_t flags = 0;
+ struct lys_module *mod = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- /* test invalid value */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &flags, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ CHECK_LOG_CTX("Parsing module \"t-status\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"invalid\" of \"value\" attribute in \"status\" element. "
"Valid values are \"current\", \"deprecated\" and \"obsolete\".", NULL, 1);
}
@@ -1354,11 +1073,20 @@ test_status_elem(void **state)
static void
test_yin_element_elem(void **state)
{
- const char *data;
- uint16_t flags = 0;
+ struct lys_module *mod = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &flags, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ CHECK_LOG_CTX("Parsing module \"t-yin-elem\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"invalid\" of \"value\" attribute in \"yin-element\" element. "
"Valid values are \"true\" and \"false\".", NULL, 1);
}
@@ -1366,61 +1094,91 @@ test_yin_element_elem(void **state)
static void
test_yangversion_elem(void **state)
{
- const char *data;
- uint8_t version = 0;
-
- /* invalid value */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &version, NULL, NULL), LY_EVALID);
- CHECK_LOG_CTX("Invalid value \"version\" of \"value\" attribute in \"yang-version\" element. "
- "Valid values are \"1\" and \"1.1\".", NULL, 1);
+ struct lys_module *mod = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ CHECK_LOG_CTX("Parsing module \"t-ver\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid value \"invalid\" of \"value\" attribute in \"yang-version\" element. Valid values are \"1\" and \"1.1\".", NULL, 1);
}
static void
test_argument_elem(void **state)
{
- const char *data;
- uint16_t flags = 0;
- const char *arg;
- struct yin_argument_meta arg_meta = {&flags, &arg};
+ struct lys_module *mod = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- /* min subelems */
- data = ELEMENT_WRAPPER_START
- ""
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &arg_meta, NULL, NULL), LY_SUCCESS);
- assert_string_equal(arg, "arg");
- assert_true(flags == 0);
- lysdict_remove(UTEST_LYCTX, arg);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_string_equal(mod->parsed->extensions->argname, "arg");
+ assert_true(mod->parsed->extensions->flags == 0);
}
static void
test_belongsto_elem(void **state)
{
- const char *data;
- struct lysp_submodule submod;
-
- lysdict_insert(UTEST_LYCTX, "module-name", 0, &PARSER_CUR_PMOD(YCTX)->mod->name);
+ struct lys_module *mod = NULL;
+ const char *parent_yin =
+ ""
+ " "
+ " "
+ " "
+ "";
+ char *submod_in =
+ ""
+ " "
+ " "
+ " "
+ "";
+ char *submod_fail =
+ ""
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &submod, NULL, NULL), LY_EVALID);
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod_fail);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, parent_yin, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"parent\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"sub\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory sub-element \"prefix\" of \"belongs-to\" element.", NULL, 1);
+
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod_in);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, parent_yin, LYS_IN_YIN, &mod));
}
static void
test_config_elem(void **state)
{
- const char *data;
- uint16_t flags = 0;
+ struct lys_module *mod = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ char buffer[256];
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &flags, NULL, NULL), LY_SUCCESS);
- assert_true(flags & LYS_CONFIG_R);
- flags = 0;
+ snprintf(buffer, sizeof(buffer), yin_data, "false");
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, &mod));
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &flags, NULL, NULL), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_data, "invalid");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, &mod));
+ CHECK_LOG_CTX("Parsing module \"config\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"invalid\" of \"value\" attribute in \"config\" element. "
"Valid values are \"true\" and \"false\".", NULL, 1);
}
@@ -1428,309 +1186,506 @@ test_config_elem(void **state)
static void
test_default_elem(void **state)
{
- const char *data;
- struct lysp_qname val = {0};
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"def\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute value of default element.", NULL, 1);
}
static void
test_err_app_tag_elem(void **state)
{
- const char *data;
- const char *val = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"err-app-tag\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute value of error-app-tag element.", NULL, 1);
}
static void
test_err_msg_elem(void **state)
{
- const char *data;
- const char *val = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"err-msg\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory sub-element \"value\" of \"error-message\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"err-msg\" failed.", NULL, 0);
CHECK_LOG_CTX("Unexpected attribute \"invalid\" of \"error-message\" element.", NULL, 1);
}
static void
test_fracdigits_elem(void **state)
{
- const char *data;
- struct lysp_type type = {0};
+ char buffer[256];
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
/* invalid values */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_data, "-1");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"frac-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-1\" of \"value\" attribute in \"fraction-digits\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_data, "02");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"frac-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"02\" of \"value\" attribute in \"fraction-digits\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_data, "1p");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"frac-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"1p\" of \"value\" attribute in \"fraction-digits\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_data, "19");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"frac-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"19\" of \"value\" attribute in \"fraction-digits\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
+ snprintf(buffer, sizeof(buffer), yin_data, "999999999999999999");
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, buffer, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"frac-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"999999999999999999\" of \"value\" attribute in \"fraction-digits\" element.", NULL, 1);
+
}
static void
test_iffeature_elem(void **state)
{
- const char *data;
- const char **iffeatures = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &iffeatures, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"feat\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute name of if-feature element.", NULL, 1);
- LY_ARRAY_FREE(iffeatures);
- iffeatures = NULL;
}
static void
test_length_elem(void **state)
{
- const char *data;
- struct lysp_type type = {0};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ struct lysp_type *type;
/* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " err-msg\n"
- " \n"
- " desc\n"
- " ref\n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " err-msg"
+ " "
+ " desc"
+ " ref"
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_RESTR(type.length, "length-str", "desc",
- "err-app-tag", "err-msg", 1, "ref");
- assert_true(type.flags & LYS_SET_LENGTH);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type.length->exts[0]), LY_STMT_LENGTH);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+
+ CHECK_LYSP_RESTR(type->length, "1..10", "desc", "err-app-tag", "err-msg", 1, "ref");
+ assert_true(type->flags & LYS_SET_LENGTH);
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type->length->exts[0]), LY_STMT_LENGTH, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START
- ""
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_RESTR(type.length, "length-str", NULL,
- NULL, NULL, 0, NULL);
- lysp_type_free(UTEST_LYCTX, &type);
- assert_true(type.flags & LYS_SET_LENGTH);
- memset(&type, 0, sizeof(type));
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+
+ CHECK_LYSP_RESTR(type->length, "1..10", NULL, NULL, NULL, 0, NULL);
+ assert_true(type->flags & LYS_SET_LENGTH);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"len-fail\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute value of length element.", NULL, 1);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
}
static void
test_modifier_elem(void **state)
{
- const char *data;
- const char *pat;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- assert_int_equal(LY_SUCCESS, lysdict_insert(UTEST_LYCTX, "\006pattern", 8, &pat));
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &pat, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"modif\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"invert\" of \"value\" attribute in \"modifier\" element. "
"Only valid value is \"invert-match\".", NULL, 1);
- lysdict_remove(UTEST_LYCTX, pat);
}
static void
test_namespace_elem(void **state)
{
- const char *data;
- const char *ns;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &ns, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"ns\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute uri of namespace element.", NULL, 1);
}
static void
test_pattern_elem(void **state)
{
- const char *data;
- struct lysp_type type = {0};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ struct lysp_type *type;
/* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " err-msg-value\n"
- " \n"
- " "pattern-desc"\n"
- " pattern-ref\n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " err-msg-value"
+ " "
+ " "pattern-desc""
+ " pattern-ref"
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- assert_true(type.flags & LYS_SET_PATTERN);
- CHECK_LYSP_RESTR(type.patterns, "\x015super_pattern", "\"pattern-desc\"",
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ assert_true(type->flags & LYS_SET_PATTERN);
+ CHECK_LYSP_RESTR(type->patterns, "\x015super_pattern", "\"pattern-desc\"",
"err-app-tag-value", "err-msg-value", 1, "pattern-ref");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type.patterns->exts[0]), LY_STMT_PATTERN);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type->patterns->exts[0]), LY_STMT_PATTERN, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START " " ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_RESTR(type.patterns, "\x006pattern", NULL, NULL, NULL, 0, NULL);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ CHECK_LYSP_RESTR(type->patterns, "\x006pattern", NULL, NULL, NULL, 0, NULL);
}
static void
test_value_position_elem(void **state)
{
- const char *data;
- struct lysp_type_enum en = {0};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
/* valid values */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_TYPE_ENUM(&(en), NULL, 0, LYS_SET_VALUE, 0, NULL, NULL, -55);
- memset(&en, 0, sizeof(en));
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_TYPE_ENUM(&(en), NULL, 0, LYS_SET_VALUE, 0, NULL, NULL, 0);
- memset(&en, 0, sizeof(en));
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_TYPE_ENUM(&(en), NULL, 0, LYS_SET_VALUE, 0, NULL, NULL, 0);
- memset(&en, 0, sizeof(en));
+ yin_data = ""
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ CHECK_LYSP_TYPE_ENUM(&(leaf->type.enums[0]), NULL, 0, LYS_SET_VALUE, 0, "e", NULL, -55);
+
+ yin_data = ""
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ CHECK_LYSP_TYPE_ENUM(&(leaf->type.enums[0]), NULL, 0, LYS_SET_VALUE, 0, "e", NULL, 0);
+
+ yin_data = ""
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ CHECK_LYSP_TYPE_ENUM(&(leaf->type.enums[0]), NULL, 0, LYS_SET_VALUE, 0, "e", NULL, 0);
/* valid positions */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_TYPE_ENUM(&(en), NULL, 0, LYS_SET_VALUE, 0, NULL, NULL, 0);
- memset(&en, 0, sizeof(en));
+ yin_data = ""
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ CHECK_LYSP_TYPE_ENUM(&(leaf->type.bits[0]), NULL, 0, LYS_SET_VALUE, 0, "b", NULL, 0);
/* invalid values */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"99999999999999999999999\" of \"value\" attribute in \"value\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"1k\" of \"value\" attribute in \"value\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"\" of \"value\" attribute in \"value\" element.", NULL, 1);
/*invalid positions */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-5\" of \"value\" attribute in \"position\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-0\" of \"value\" attribute in \"position\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"99999999999999999999\" of \"value\" attribute in \"position\" element.", NULL, 1);
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &en, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"vp5\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"\" of \"value\" attribute in \"position\" element.", NULL, 1);
}
static void
test_prefix_elem(void **state)
{
- const char *data;
- const char *value = NULL;
+ struct lys_module *mod = NULL;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &value, NULL, NULL), LY_SUCCESS);
- assert_string_equal(value, "pref");
- lysdict_remove(UTEST_LYCTX, value);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_string_equal(mod->prefix, "pref");
}
static void
test_range_elem(void **state)
{
- const char *data;
- struct lysp_type type = {0};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ struct lysp_type *type;
/* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " err-msg\n"
- " \n"
- " desc\n"
- " ref\n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " err-msg"
+ " "
+ " desc"
+ " ref"
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_RESTR(type.range, "range-str", "desc",
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ assert_true(type->flags & LYS_SET_RANGE);
+ CHECK_LYSP_RESTR(type->range, "1..10", "desc",
"err-app-tag", "err-msg", 1, "ref");
- assert_true(type.flags & LYS_SET_RANGE);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type.range->exts[0]), LY_STMT_RANGE);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type->range->exts[0]), LY_STMT_RANGE, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_RESTR(type.range, "range-str", NULL,
- NULL, NULL, 0, NULL);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ CHECK_LYSP_RESTR(type->range, "1..10", NULL, NULL, NULL, 0, NULL);
}
static void
test_reqinstance_elem(void **state)
{
- const char *data;
- struct lysp_type type = {0};
-
- data = ELEMENT_WRAPPER_START "" EXT_SUBELEM "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- assert_int_equal(type.require_instance, 1);
- assert_true(type.flags & LYS_SET_REQINST);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type.exts[0]), LY_STMT_REQUIRE_INSTANCE);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- assert_int_equal(type.require_instance, 0);
- assert_true(type.flags & LYS_SET_REQINST);
- memset(&type, 0, sizeof(type));
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_EVALID);
- memset(&type, 0, sizeof(type));
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ struct lysp_type *type;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ EXT_SUBELEM
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ assert_int_equal(type->require_instance, 1);
+ assert_true(type->flags & LYS_SET_REQINST);
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type->exts[0]), LY_STMT_REQUIRE_INSTANCE, "MY_MTU");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ type = &leaf->type;
+ assert_int_equal(type->require_instance, 0);
+ assert_true(type->flags & LYS_SET_REQINST);
+
+ /* invalid */
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"req-mod3\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"invalid\" of \"value\" attribute in \"require-instance\" element. "
"Valid values are \"true\" and \"false\".", NULL, 1);
}
@@ -1738,189 +1693,247 @@ test_reqinstance_elem(void **state)
static void
test_revision_date_elem(void **state)
{
- const char *data;
- char rev[LY_REV_SIZE];
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lys_module *dummy = NULL;
+
+ const char *dummy_mod =
+ ""
+ " "
+ " "
+ " "
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, rev, NULL, NULL), LY_SUCCESS);
- assert_string_equal(rev, "2000-01-01");
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, dummy_mod, LYS_IN_YIN, &dummy));
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, rev, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_string_equal(mod->parsed->imports[0].rev, "2000-01-01");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"rev-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"2000-50-05\" of \"revision-date\".", NULL, 1);
}
static void
test_unique_elem(void **state)
{
- const char *data;
- const char **values = NULL;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &values, NULL, NULL), LY_SUCCESS);
- assert_string_equal(*values, "tag");
- lysdict_remove(UTEST_LYCTX, *values);
- LY_ARRAY_FREE(values);
- values = NULL;
+ struct lys_module *mod = NULL;
+ struct lysp_node_list *list;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ list = (struct lysp_node_list *)mod->parsed->data;
+ assert_string_equal(list->uniques[0].str, "tag");
}
static void
test_units_elem(void **state)
{
- const char *data;
- const char *values = NULL;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &values, NULL, NULL), LY_SUCCESS);
- assert_string_equal(values, "name");
- lysdict_remove(UTEST_LYCTX, values);
- values = NULL;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
+ const char *yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ assert_string_equal(leaf->units, "name");
}
static void
test_yin_text_value_elem(void **state)
{
- const char *data;
- const char *val;
-
- data = ELEMENT_WRAPPER_START "text" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_SUCCESS);
- assert_string_equal(val, "text");
- lysdict_remove(UTEST_LYCTX, val);
-
- data = " text ";
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_SUCCESS);
- assert_string_equal(val, "text");
- lysdict_remove(UTEST_LYCTX, val);
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_SUCCESS);
- assert_string_equal("", val);
- lysdict_remove(UTEST_LYCTX, val);
-}
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_leaf *leaf;
-static void
-test_type_elem(void **state)
-{
- const char *data;
- struct lysp_type type = {0};
+ yin_data =
+ ""
+ " "
+ " "
+ " text"
+ "";
- /* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- assert_string_equal(type.name, "type-name");
- assert_string_equal(*type.bases, "base-name");
- assert_string_equal(type.bits->name, "bit");
- assert_string_equal(type.enums->name, "enum");
- assert_int_equal(type.fraction_digits, 2);
- CHECK_LYSP_RESTR(type.length, "length", NULL,
- NULL, NULL, 0, NULL);
- assert_string_equal(type.path->expr, "/path");
- CHECK_LYSP_RESTR(type.patterns, "\006pattern", NULL,
- NULL, NULL, 0, NULL);
- CHECK_LYSP_RESTR(type.range, "range", NULL,
- NULL, NULL, 0, NULL);
- assert_int_equal(type.require_instance, 1);
- assert_string_equal(type.types->name, "sub-type-name");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(type.exts[0]), LY_STMT_TYPE);
- assert_true(type.flags & LYS_SET_BASE);
- assert_true(type.flags & LYS_SET_BIT);
- assert_true(type.flags & LYS_SET_ENUM);
- assert_true(type.flags & LYS_SET_FRDIGITS);
- assert_true(type.flags & LYS_SET_LENGTH);
- assert_true(type.flags & LYS_SET_PATH);
- assert_true(type.flags & LYS_SET_PATTERN);
- assert_true(type.flags & LYS_SET_RANGE);
- assert_true(type.flags & LYS_SET_REQINST);
- assert_true(type.flags & LYS_SET_TYPE);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_string_equal(mod->dsc, "text");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " text"
+ " "
+ " "
+ "";
- /* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &type, NULL, NULL), LY_SUCCESS);
- lysp_type_free(UTEST_LYCTX, &type);
- memset(&type, 0, sizeof(type));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ leaf = (struct lysp_node_leaf *)mod->parsed->data;
+ assert_string_equal(leaf->musts->emsg, "text");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_string_equal(mod->dsc, "");
}
static void
test_max_elems_elem(void **state)
{
- const char *data;
- struct lysp_node_list list = {0};
- struct lysp_refine refine = {0};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_uses *uses;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = " ";
- assert_int_equal(test_element_helper(state, data, &refine, NULL, NULL), LY_SUCCESS);
- assert_int_equal(refine.max, 10);
- assert_true(refine.flags & LYS_SET_MAX);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ uses = (struct lysp_node_uses *)mod->parsed->data;
+ assert_int_equal(uses->refines->max, 10);
+ assert_true(uses->refines->flags & LYS_SET_MAX);
- data = "
";
- assert_int_equal(test_element_helper(state, data, &list, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "
";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"max-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"0\" of \"value\" attribute in \"max-elements\" element.", NULL, 1);
- data = "
";
- assert_int_equal(test_element_helper(state, data, &list, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "
";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"max-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"-10\" of \"value\" attribute in \"max-elements\" element.", NULL, 1);
- data = "
";
- assert_int_equal(test_element_helper(state, data, &list, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "
";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"max-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"k\" of \"value\" attribute in \"max-elements\" element.", NULL, 1);
- data = "
";
- assert_int_equal(test_element_helper(state, data, &list, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "
";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"max-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"u12\" of \"value\" attribute in \"max-elements\" element.", NULL, 1);
}
static void
test_min_elems_elem(void **state)
{
- const char *data;
- struct lysp_node_leaflist llist = {0};
+ const char *yin_data;
- data = " ";
- assert_int_equal(test_element_helper(state, data, &llist, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"min-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Value \"-5\" of \"value\" attribute in \"min-elements\" element is out of bounds.", NULL, 1);
- data = " ";
- assert_int_equal(test_element_helper(state, data, &llist, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"min-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Value \"99999999999999999\" of \"value\" attribute in \"min-elements\" element is out of bounds.", NULL, 1);
- data = " ";
- assert_int_equal(test_element_helper(state, data, &llist, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"min-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"5k\" of \"value\" attribute in \"min-elements\" element.", NULL, 1);
- data = " ";
- assert_int_equal(test_element_helper(state, data, &llist, NULL, NULL), LY_EVALID);
+ yin_data = ""
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"min-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"05\" of \"value\" attribute in \"min-elements\" element.", NULL, 1);
}
static void
test_ordby_elem(void **state)
{
- const char *data;
- uint16_t flags = 0;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &flags, NULL, NULL), LY_SUCCESS);
- assert_true(flags & LYS_ORDBY_USER);
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_list *list;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ "";
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &flags, NULL, NULL), LY_EVALID);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ list = (struct lysp_node_list *)mod->parsed->data;
+ assert_true(list->flags & LYS_ORDBY_USER);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"ord-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"inv\" of \"value\" attribute in \"ordered-by\" element. "
"Valid values are \"system\" and \"user\".", NULL, 1);
}
@@ -1928,390 +1941,503 @@ test_ordby_elem(void **state)
static void
test_any_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_anydata *parsed = NULL;
- uint16_t flags;
+ uint16_t flags = LYS_CONFIG_W | LYS_MAND_TRUE | LYS_STATUS_DEPRC;
/* anyxml max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_anydata *)siblings;
- flags = LYS_CONFIG_W | LYS_MAND_TRUE | LYS_STATUS_DEPRC;
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_anydata *)mod->parsed->data;
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "any-name", 0, LYS_ANYXML, 0, "ref", 1);
+ "any-name", 0, LYS_ANYXML, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "feature");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_ANYXML);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_ANYXML, "MY_MTU");
/* anydata max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_anydata *)siblings;
- flags = LYS_CONFIG_W | LYS_MAND_TRUE | LYS_STATUS_DEPRC;
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_anydata *)mod->parsed->data;
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "any-name", 0, LYS_ANYDATA, 0, "ref", 1);
+ "any-name", 0, LYS_ANYDATA, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "feature");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_ANYDATA);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_ANYDATA, "MY_MTU");
/* min subelems */
- node_meta.parent = (void *)0x10;
- data = ELEMENT_WRAPPER_START " " ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_anydata *)siblings;
- assert_ptr_equal(parsed->parent, node_meta.parent);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_anydata *)mod->parsed->data;
CHECK_LYSP_NODE(parsed, NULL, 0, 0, 0,
- "any-name", 0, LYS_ANYDATA, 1, NULL, 0);
- lysp_node_free(UTEST_LYCTX, siblings);
+ "any-name", 0, LYS_ANYDATA, 0, NULL);
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 0);
}
static void
test_leaf_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_leaf *parsed = NULL;
uint16_t flags;
/* max elements */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_leaf *)siblings;
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_leaf *)mod->parsed->data;
flags = LYS_CONFIG_W | LYS_MAND_TRUE | LYS_STATUS_DEPRC;
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "leaf", 0, LYS_LEAF, 0, "ref", 1);
+ "leaf1", 1, LYS_LEAF, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "feature");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LEAF);
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LEAF, "MY_MTU");
assert_string_equal(parsed->musts->arg.str, "must-cond");
- assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->type.name, "string");
assert_string_equal(parsed->units, "uni");
+
+ parsed = (struct lysp_node_leaf *)parsed->next;
+ assert_string_equal(parsed->name, "leaf2");
assert_string_equal(parsed->dflt.str, "def-val");
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
/* min elements */
- data = ELEMENT_WRAPPER_START " " ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_leaf *)siblings;
+ yin_data = ""
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_leaf *)mod->parsed->data;
assert_string_equal(parsed->name, "leaf");
- assert_string_equal(parsed->type.name, "type");
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ assert_string_equal(parsed->type.name, "string");
}
static void
test_leaf_list_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_leaflist *parsed = NULL;
uint16_t flags;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_leaflist *)siblings;
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_leaflist *)mod->parsed->data;
flags = LYS_CONFIG_W | LYS_ORDBY_USER | LYS_STATUS_CURR | LYS_SET_MAX;
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "llist", 0, LYS_LEAFLIST, 0, "ref", 1);
+ "llist", 0, LYS_LEAFLIST, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_RESTR(parsed->musts, "must-cond", NULL, NULL, NULL, 0, NULL);
assert_string_equal(parsed->dflts[0].str, "def-val0");
assert_string_equal(parsed->dflts[1].str, "def-val1");
assert_string_equal(parsed->iffeatures[0].str, "feature");
assert_int_equal(parsed->max, 5);
- assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->type.name, "string");
assert_string_equal(parsed->units, "uni");
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LEAF_LIST);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LEAF_LIST, "MY_MTU");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_leaflist *)siblings;
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_leaflist *)mod->parsed->data;
flags = LYS_CONFIG_W | LYS_ORDBY_USER | LYS_STATUS_CURR | LYS_SET_MIN;
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "llist", 0, LYS_LEAFLIST, 0, "ref", 1);
+ "llist", 0, LYS_LEAFLIST, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_RESTR(parsed->musts, "must-cond", NULL, NULL, NULL, 0, NULL);
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "feature");
assert_int_equal(parsed->min, 5);
- assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->type.name, "string");
assert_string_equal(parsed->units, "uni");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LEAF_LIST);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_leaflist *)siblings;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LEAF_LIST, "MY_MTU");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_leaflist *)mod->parsed->data;
flags = LYS_CONFIG_W | LYS_ORDBY_USER | LYS_STATUS_CURR | LYS_SET_MIN | LYS_SET_MAX;
CHECK_LYSP_NODE(parsed, "desc", 0, flags, 1,
- "llist", 0, LYS_LEAFLIST, 0, "ref", 1);
+ "llist", 0, LYS_LEAFLIST, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_RESTR(parsed->musts, "must-cond", NULL, NULL, NULL, 0, NULL);
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "feature");
assert_int_equal(parsed->min, 5);
assert_int_equal(parsed->max, 15);
- assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->type.name, "string");
assert_string_equal(parsed->units, "uni");
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_leaflist *)siblings;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_leaflist *)mod->parsed->data;
assert_string_equal(parsed->name, "llist");
- assert_string_equal(parsed->type.name, "type");
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ assert_string_equal(parsed->type.name, "string");
/* invalid combinations */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " "
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"ll-inv\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid combination of min-elements and max-elements: min value 15 is bigger than the max value 5.",
- NULL, 4);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_EVALID);
- CHECK_LOG_CTX("Invalid combination of sub-elemnts \"min-elements\" and \"default\" in \"leaf-list\" element.", NULL, 5);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
-
- data = ELEMENT_WRAPPER_START
- ""
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_EVALID);
+ NULL, 1);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"ll-inv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid combination of sub-elemnts \"min-elements\" and \"default\" in \"leaf-list\" element.", NULL, 1);
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"ll-inv\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory sub-element \"type\" of \"leaf-list\" element.", NULL, 1);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
}
static void
test_presence_elem(void **state)
{
- const char *data;
- const char *val;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_SUCCESS);
- assert_string_equal(val, "presence-val");
- lysdict_remove(UTEST_LYCTX, val);
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_EVALID);
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_container *cont;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ cont = (struct lysp_node_container *)mod->parsed->data;
+ assert_string_equal(cont->presence, "presence-val");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"pres-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute value of presence element.", NULL, 1);
}
static void
test_key_elem(void **state)
{
- const char *data;
- const char *val;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_SUCCESS);
- assert_string_equal(val, "key-value");
- lysdict_remove(UTEST_LYCTX, val);
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &val, NULL, NULL), LY_EVALID);
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_list *list;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ list = (struct lysp_node_list *)mod->parsed->data;
+ assert_string_equal(list->key, "key-value");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "
"
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"key-mod2\" failed.", NULL, 0);
CHECK_LOG_CTX("Missing mandatory attribute value of key element.", NULL, 1);
}
static void
test_uses_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {NULL, &siblings};
- struct lysp_node_uses *parsed = NULL;
+ struct lys_module *mod;
+ struct lysp_node_uses *parsed;
+ const char *yin_data;
/* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " ref\n"
- " \n"
- " \n"
- EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_uses *)&siblings[0];
- CHECK_LYSP_NODE(parsed, "desc", 1, LYS_STATUS_OBSLT, 1,
- "uses-name", 0, LYS_USES, 0, "ref", 1);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_uses *)mod->parsed->data;
+ CHECK_LYSP_NODE(parsed, "desc", 0, LYS_STATUS_OBSLT, 1,
+ "uses-name", 0, LYS_USES, 0, "ref");
CHECK_LYSP_WHEN(parsed->when, "cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "feature");
assert_string_equal(parsed->refines->nodeid, "target");
assert_string_equal(parsed->augments->nodeid, "target");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_USES);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- assert_string_equal(siblings[0].name, "uses-name");
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_uses *)mod->parsed->data;
+ assert_string_equal(parsed->name, "uses-name");
}
static void
test_list_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {NULL, &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_list *parsed = NULL;
+ uint16_t flags = LYS_ORDBY_USER | LYS_STATUS_DEPRC | LYS_CONFIG_W | LYS_SET_MIN;
/* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " "
EXT_SUBELEM
- "
"
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_list *)&siblings[0];
+ " "
+ " "
+ "
"
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_list *)mod->parsed->data;
+
assert_string_equal(parsed->child->name, "anyd");
assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
assert_string_equal(parsed->child->next->name, "anyx");
@@ -2326,13 +2452,16 @@ test_list_elem(void **state)
assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
assert_string_equal(parsed->child->next->next->next->next->next->next->name, "sub-list");
assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_LIST);
- assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "uses-name");
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "grp");
assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_USES);
- assert_null(parsed->child->next->next->next->next->next->next->next->next);
- uint16_t flags = LYS_ORDBY_USER | LYS_STATUS_DEPRC | LYS_CONFIG_W | LYS_SET_MIN;
-
- CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "list-name", 0, LYS_LIST, 0, "ref", 1);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->next->name, "key");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->next->next->name, "utag");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->next->next->next->nodetype, LYS_LEAF);
+ assert_null(parsed->child->next->next->next->next->next->next->next->next->next->next);
+
+ CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1, "list-name", 0, LYS_LIST, 0, "ref");
+ CHECK_POINTER(parsed->when, 1);
CHECK_LYSP_RESTR(parsed->musts, "must-cond", NULL, NULL, NULL, 0, NULL);
CHECK_LYSP_WHEN(parsed->when, "when", NULL, 0, NULL);
assert_string_equal(parsed->groupings->name, "grp");
@@ -2344,51 +2473,67 @@ test_list_elem(void **state)
assert_int_equal(parsed->min, 10);
assert_string_equal(parsed->typedefs->name, "tpdf");
assert_string_equal(parsed->uniques->str, "utag");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LIST);
- lysp_node_free(UTEST_LYCTX, siblings);
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- siblings = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_LIST, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "
" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_list *)&siblings[0];
- CHECK_LYSP_NODE(parsed, NULL, 0, 0, 0,
- "list-name", 0, LYS_LIST, 0, NULL, 0);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "
"
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_list *)mod->parsed->data;
+ CHECK_LYSP_NODE(parsed, NULL, 0, LYS_CONFIG_R, 0, "list-name", 0, LYS_LIST, 0, NULL);
+ CHECK_POINTER(parsed->when, 0);
}
static void
test_notification_elem(void **state)
{
- const char *data;
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_notif *notifs = NULL;
- struct tree_node_meta notif_meta = {NULL, (struct lysp_node **)¬ifs};
/* max subelems */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, ¬if_meta, NULL, NULL), LY_SUCCESS);
+ "
"
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+
+ notifs = mod->parsed->notifs;
+
assert_string_equal(notifs->name, "notif-name");
assert_string_equal(notifs->child->name, "anyd");
assert_int_equal(notifs->child->nodetype, LYS_ANYDATA);
@@ -2416,47 +2561,61 @@ test_notification_elem(void **state)
assert_null(notifs->parent);
assert_string_equal(notifs->ref, "ref");
assert_string_equal(notifs->typedefs->name, "tpdf");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(notifs->exts[0]), LY_STMT_NOTIFICATION);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)notifs);
- notifs = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(notifs->exts[0]), LY_STMT_NOTIFICATION, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, ¬if_meta, NULL, NULL), LY_SUCCESS);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ notifs = mod->parsed->notifs;
assert_string_equal(notifs->name, "notif-name");
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)notifs);
- notifs = NULL;
}
static void
test_grouping_elem(void **state)
{
- const char *data;
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_grp *grps = NULL;
- struct tree_node_meta grp_meta = {NULL, (struct lysp_node **)&grps};
/* max subelems */
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &grp_meta, NULL, NULL), LY_SUCCESS);
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ grps = &mod->parsed->groupings[0];
+
assert_string_equal(grps->name, "grp-name");
assert_string_equal(grps->child->name, "anyd");
assert_string_equal(grps->child->next->name, "anyx");
@@ -2478,66 +2637,83 @@ test_grouping_elem(void **state)
assert_int_equal(grps->child->next->next->next->next->next->next->nodetype, LYS_CONTAINER);
assert_string_equal(grps->child->next->next->next->next->next->next->next->name, "choice");
assert_int_equal(grps->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(grps->exts[0]), LY_STMT_GROUPING);
- lysp_node_free(UTEST_LYCTX, &grps->node);
- grps = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(grps->exts[0]), LY_STMT_GROUPING, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &grp_meta, NULL, NULL), LY_SUCCESS);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ grps = mod->parsed->groupings;
assert_string_equal(grps->name, "grp-name");
- lysp_node_free(UTEST_LYCTX, &grps->node);
- grps = NULL;
}
static void
test_container_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {NULL, &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_container *parsed = NULL;
+ uint16_t flags = LYS_CONFIG_W | LYS_STATUS_CURR;
/* max subelems */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_container *)siblings;
- uint16_t flags = LYS_CONFIG_W | LYS_STATUS_CURR;
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+
+ parsed = (struct lysp_node_container *)mod->parsed->data;
+ while (parsed && strcmp(parsed->name, "cont-name") != 0) {
+ parsed = (struct lysp_node_container *)parsed->next;
+ }
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "cont-name", 0, LYS_CONTAINER, 0, "ref", 1);
+ "cont-name", 0, LYS_CONTAINER, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
CHECK_LYSP_RESTR(parsed->musts, "cond", NULL, NULL, NULL, 0, NULL);
CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "iff");
assert_string_equal(parsed->presence, "presence");
assert_string_equal(parsed->typedefs->name, "tpdf");
- assert_string_equal(parsed->groupings->name, "sub-grp");
+ assert_string_equal(parsed->groupings->name, "grp");
assert_string_equal(parsed->child->name, "anyd");
assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
assert_string_equal(parsed->child->next->name, "anyx");
@@ -2550,63 +2726,83 @@ test_container_elem(void **state)
assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAFLIST);
assert_string_equal(parsed->child->next->next->next->next->next->name, "list");
assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LIST);
- assert_string_equal(parsed->child->next->next->next->next->next->next->name, "uses-name");
+ assert_string_equal(parsed->child->next->next->next->next->next->next->name, "grp");
assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_USES);
assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "choice");
assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
assert_null(parsed->child->next->next->next->next->next->next->next->next);
assert_string_equal(parsed->notifs->name, "notf");
assert_string_equal(parsed->actions->name, "act");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_CONTAINER);
- lysp_node_free(UTEST_LYCTX, siblings);
- ly_set_erase(&YCTX->tpdfs_nodes, NULL);
- siblings = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_CONTAINER, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_container *)siblings;
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_container *)mod->parsed->data;
CHECK_LYSP_NODE(parsed, NULL, 0, 0, 0,
- "cont-name", 0, LYS_CONTAINER, 0, NULL, 0);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ "cont-name", 0, LYS_CONTAINER, 0, NULL);
+ CHECK_POINTER(parsed->when, 0);
}
static void
test_case_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {NULL, &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node *node = NULL;
struct lysp_node_case *parsed = NULL;
+ uint16_t flags = LYS_STATUS_CURR;
/* max subelems */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ "
"
+ " ref"
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_case *)siblings;
- uint16_t flags = LYS_STATUS_CURR;
+ "
"
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+
+ node = mod->parsed->data;
+ while (node && strcmp(node->name, "ch") != 0) {
+ node = node->next;
+ }
+ parsed = (struct lysp_node_case *)((struct lysp_node_choice *)node)->child;
CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "case-name", 0, LYS_CASE, 0, "ref", 1);
- CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
+ "case-name", 0, LYS_CASE, 1, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
+ CHECK_LYSP_WHEN(parsed->when, "/c1:cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "iff");
assert_string_equal(parsed->child->name, "anyd");
assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
@@ -2625,58 +2821,80 @@ test_case_elem(void **state)
assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "choice");
assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
assert_null(parsed->child->next->next->next->next->next->next->next->next);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_CASE);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_CASE, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_case *)siblings;
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_case *)((struct lysp_node_choice *)mod->parsed->data)->child;
CHECK_LYSP_NODE(parsed, NULL, 0, 0, 0,
- "case-name", 0, LYS_CASE, 0, NULL, 0);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ "case-name", 0, LYS_CASE, 1, NULL);
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 0);
}
static void
test_choice_elem(void **state)
{
- const char *data;
- struct lysp_node *siblings = NULL;
- struct tree_node_meta node_meta = {NULL, &siblings};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node *node = NULL;
struct lysp_node_choice *parsed = NULL;
+ uint16_t flags = LYS_CONFIG_W | LYS_MAND_TRUE | LYS_STATUS_CURR;
/* max subelems */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " ref"
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_choice *)siblings;
- uint16_t flags = LYS_CONFIG_W | LYS_MAND_TRUE | LYS_STATUS_CURR;
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1,
- "choice-name", 0, LYS_CHOICE, 0, "ref", 1);
- CHECK_LYSP_WHEN(parsed->when, "when-cond", NULL, 0, NULL);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+
+ node = mod->parsed->data;
+ while (node && strcmp(node->name, "choice-name") != 0) {
+ node = node->next;
+ }
+ parsed = (struct lysp_node_choice *)node;
+
+ CHECK_LYSP_NODE(parsed, "desc", 1, flags, 1, "choice-name", 1, LYS_CHOICE, 0, "ref");
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 1);
+ CHECK_LYSP_WHEN(parsed->when, "/ch1:cond", NULL, 0, NULL);
assert_string_equal(parsed->iffeatures[0].str, "iff");
assert_string_equal(parsed->child->name, "anyd");
assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
@@ -2695,402 +2913,514 @@ test_choice_elem(void **state)
assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "list");
assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_LIST);
assert_null(parsed->child->next->next->next->next->next->next->next->next);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_CHOICE);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(parsed->exts[0]), LY_STMT_CHOICE, "MY_MTU");
+
+ parsed = (struct lysp_node_choice *)parsed->next;
+ assert_string_equal(parsed->name, "choice2");
+ assert_string_equal(parsed->dflt.str, "sub-case");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &node_meta, NULL, NULL), LY_SUCCESS);
- parsed = (struct lysp_node_choice *)siblings;
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ parsed = (struct lysp_node_choice *)mod->parsed->data;
assert_string_equal(parsed->name, "choice-name");
- CHECK_LYSP_NODE(parsed, NULL, 0, 0, 0,
- "choice-name", 0, LYS_CHOICE, 0, NULL, 0);
- lysp_node_free(UTEST_LYCTX, siblings);
- siblings = NULL;
+ CHECK_LYSP_NODE(parsed, NULL, 0, 0, 0, "choice-name", 0, LYS_CHOICE, 0, NULL);
+ CHECK_POINTER(((struct lysp_node_leaf *)parsed)->when, 0);
}
static void
test_inout_elem(void **state)
{
- const char *data;
- struct lysp_node_action_inout inout = {0};
- struct inout_meta inout_meta = {NULL, &inout};
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_node_action *rpc = NULL;
+ struct lysp_node_action_inout *inout = NULL;
/* max subelements */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &inout_meta, NULL, NULL), LY_SUCCESS);
- CHECK_LYSP_ACTION_INOUT(&(inout), 1, 1, 1, 1, LYS_INPUT, 0, 1);
- CHECK_LYSP_RESTR(inout.musts, "cond", NULL, NULL, NULL, 0, NULL);
- assert_string_equal(inout.typedefs->name, "tpdf");
- assert_string_equal(inout.groupings->name, "sub-grp");
- assert_string_equal(inout.child->name, "anyd");
- assert_int_equal(inout.child->nodetype, LYS_ANYDATA);
- assert_string_equal(inout.child->next->name, "anyx");
- assert_int_equal(inout.child->next->nodetype, LYS_ANYXML);
- assert_string_equal(inout.child->next->next->name, "choice");
- assert_int_equal(inout.child->next->next->nodetype, LYS_CHOICE);
- assert_string_equal(inout.child->next->next->next->name, "subcont");
- assert_int_equal(inout.child->next->next->next->nodetype, LYS_CONTAINER);
- assert_string_equal(inout.child->next->next->next->next->name, "leaf");
- assert_int_equal(inout.child->next->next->next->next->nodetype, LYS_LEAF);
- assert_string_equal(inout.child->next->next->next->next->next->name, "llist");
- assert_int_equal(inout.child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
- assert_string_equal(inout.child->next->next->next->next->next->next->name, "list");
- assert_int_equal(inout.child->next->next->next->next->next->next->nodetype, LYS_LIST);
- assert_string_equal(inout.child->next->next->next->next->next->next->next->name, "uses-name");
- assert_int_equal(inout.child->next->next->next->next->next->next->next->nodetype, LYS_USES);
- assert_null(inout.child->next->next->next->next->next->next->next->next);
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(inout.exts[0]), LY_STMT_INPUT);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)&inout);
- memset(&inout, 0, sizeof inout);
+ " "
+ "
"
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ rpc = mod->parsed->rpcs;
+ inout = &rpc->input;
+
+ CHECK_LYSP_ACTION_INOUT(inout, 1, 1, 1, 1, LYS_INPUT, 1, 1);
+ CHECK_LYSP_RESTR(inout->musts, "/io1:cond", NULL, NULL, NULL, 0, NULL);
+ assert_string_equal(inout->typedefs->name, "tpdf");
+ assert_string_equal(inout->groupings->name, "sub-grp");
+ assert_string_equal(inout->child->name, "anyd");
+ assert_int_equal(inout->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(inout->child->next->name, "anyx");
+ assert_int_equal(inout->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(inout->child->next->next->name, "choice");
+ assert_int_equal(inout->child->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(inout->child->next->next->next->name, "subcont");
+ assert_int_equal(inout->child->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(inout->child->next->next->next->next->name, "leaf");
+ assert_int_equal(inout->child->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(inout->child->next->next->next->next->next->name, "llist");
+ assert_int_equal(inout->child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(inout->child->next->next->next->next->next->next->name, "list");
+ assert_int_equal(inout->child->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(inout->child->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(inout->child->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(inout->child->next->next->next->next->next->next->next->next);
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(inout->exts[0]), LY_STMT_INPUT, "MY_MTU");
/* max subelements */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- ""
+ " "
+ "";
- /* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &inout_meta, NULL, NULL), LY_SUCCESS);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)&inout);
- memset(&inout, 0, sizeof inout);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ rpc = mod->parsed->rpcs;
+ inout = &rpc->output;
+
+ CHECK_LYSP_ACTION_INOUT(inout, 1, 1, 1, 1, LYS_OUTPUT, 1, 1);
+ assert_string_equal(inout->musts->arg.str, "/io2:cond");
+ assert_string_equal(inout->typedefs->name, "tpdf");
+ assert_string_equal(inout->groupings->name, "sub-grp");
+ assert_string_equal(inout->child->name, "anyd");
+ assert_int_equal(inout->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(inout->child->next->name, "anyx");
+ assert_int_equal(inout->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(inout->child->next->next->name, "choice");
+ assert_int_equal(inout->child->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(inout->child->next->next->next->name, "subcont");
+ assert_int_equal(inout->child->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(inout->child->next->next->next->next->name, "leaf");
+ assert_int_equal(inout->child->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(inout->child->next->next->next->next->next->name, "llist");
+ assert_int_equal(inout->child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(inout->child->next->next->next->next->next->next->name, "list");
+ assert_int_equal(inout->child->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(inout->child->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(inout->child->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(inout->exts[0]), LY_STMT_OUTPUT, "MY_MTU");
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &inout_meta, NULL, NULL), LY_SUCCESS);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)&inout);
- memset(&inout, 0, sizeof inout);
+ /* min subelems */
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
/* invalid combinations */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &inout_meta, NULL, NULL), LY_EVALID);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)&inout);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"io-mod5\" failed.", NULL, 0);
CHECK_LOG_CTX("Unexpected attribute \"name\" of \"input\" element.", NULL, 1);
- memset(&inout, 0, sizeof inout);
}
static void
test_action_elem(void **state)
{
- const char *data;
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_action *actions = NULL;
- struct tree_node_meta act_meta = {NULL, (struct lysp_node **)&actions};
- uint16_t flags;
+ struct lysp_node_container *cont = NULL;
+ uint16_t flags = LYS_STATUS_DEPRC;
/* max subelems */
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- /* there must be parent for action */
- act_meta.parent = (void *)1;
- assert_int_equal(test_element_helper(state, data, &act_meta, NULL, NULL), LY_SUCCESS);
- act_meta.parent = NULL;
- flags = LYS_STATUS_DEPRC;
- CHECK_LYSP_ACTION(actions, "desc", 1, flags, 1, 1,\
- 1, 0, 0, 0,\
- 1, 0,\
- "act", LYS_ACTION, \
- 1, 0, 0, 1,\
- 1, 0,\
- 1, "ref", 1);
-
+ " "
+ "
"
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ cont = (struct lysp_node_container *)mod->parsed->data;
+ while (cont && strcmp(cont->name, "c") != 0) {
+ cont = (struct lysp_node_container *)cont->next;
+ }
+ actions = cont->actions;
+ CHECK_LYSP_ACTION(actions, "desc", 1, flags, 1, 1, 1, 0, 0, 0, 1, 0,
+ "act", LYS_ACTION, 1, 0, 0, 1, 1, 0, 1, "ref", 1);
assert_string_equal(actions->iffeatures[0].str, "iff");
assert_string_equal(actions->typedefs->name, "tpdf");
assert_string_equal(actions->groupings->name, "grouping");
- assert_string_equal(actions->output.musts->arg.str, "cond");
+ assert_string_equal(actions->output.musts->arg.str, "/a1:cond");
assert_string_equal(actions->input.child->name, "uses-name");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(actions->exts[0]), LY_STMT_ACTION);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)actions);
- actions = NULL;
-
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(actions->exts[0]), LY_STMT_ACTION, "MY_MTU");
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ " "
+ " ref"
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &act_meta, NULL, NULL), LY_SUCCESS);
- flags = LYS_STATUS_DEPRC;
- CHECK_LYSP_ACTION(actions, "desc", 1, flags, 1, 1,\
- 1, 0, 0, 0,\
- 1, 0,\
- "act", LYS_RPC, \
- 1, 0, 0, 1,\
- 1, 0,\
- 0, "ref", 1);
-
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ actions = mod->parsed->rpcs;
+ CHECK_LYSP_ACTION(actions, "desc", 1, flags, 1, 1, 1, 0, 0, 0, 1, 0, "act", LYS_RPC, 1, 0, 0, 1, 1, 0, 0, "ref", 1);
assert_string_equal(actions->iffeatures[0].str, "iff");
assert_string_equal(actions->typedefs->name, "tpdf");
assert_string_equal(actions->groupings->name, "grouping");
assert_string_equal(actions->input.child->name, "uses-name");
- assert_string_equal(actions->output.musts->arg.str, "cond");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(actions->exts[0]), LY_STMT_RPC);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)actions);
- actions = NULL;
+ assert_string_equal(actions->output.musts->arg.str, "/a2:cond");
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(actions->exts[0]), LY_STMT_RPC, "MY_MTU");
/* min subelems */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &act_meta, NULL, NULL), LY_SUCCESS);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ cont = (struct lysp_node_container *)mod->parsed->data;
+ actions = cont->actions;
assert_string_equal(actions->name, "act");
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)actions);
- actions = NULL;
}
static void
test_augment_elem(void **state)
{
- const char *data;
+ const char *yin_data;
+ struct lys_module *mod = NULL;
struct lysp_node_augment *augments = NULL;
- struct tree_node_meta aug_meta = {NULL, (struct lysp_node **)&augments};
-
- PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " desc\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " ref\n"
- " \n"
- " \n"
- " \n"
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " desc"
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " ref"
+ " "
+ " "
+ " "
EXT_SUBELEM
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &aug_meta, NULL, NULL), LY_SUCCESS);
- assert_string_equal(augments->nodeid, "target");
+ "
"
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+
+ augments = mod->parsed->augments;
+
+ assert_string_equal(augments->nodeid, "/aug-test:target");
assert_null(augments->parent);
assert_int_equal(augments->nodetype, LYS_AUGMENT);
assert_true(augments->flags & LYS_STATUS_CURR);
assert_string_equal(augments->dsc, "desc");
assert_string_equal(augments->ref, "ref");
- assert_string_equal(augments->when->cond, "when-cond");
+ assert_string_equal(augments->when->cond, "/aug-test:when-cond");
assert_string_equal(augments->iffeatures[0].str, "iff");
assert_string_equal(augments->child->name, "anyd");
assert_int_equal(augments->child->nodetype, LYS_ANYDATA);
assert_string_equal(augments->child->next->name, "anyx");
assert_int_equal(augments->child->next->nodetype, LYS_ANYXML);
- assert_string_equal(augments->child->next->next->name, "case");
- assert_int_equal(augments->child->next->next->nodetype, LYS_CASE);
- assert_string_equal(augments->child->next->next->next->name, "choice");
- assert_int_equal(augments->child->next->next->next->nodetype, LYS_CHOICE);
- assert_string_equal(augments->child->next->next->next->next->name, "subcont");
- assert_int_equal(augments->child->next->next->next->next->nodetype, LYS_CONTAINER);
- assert_string_equal(augments->child->next->next->next->next->next->name, "leaf");
- assert_int_equal(augments->child->next->next->next->next->next->nodetype, LYS_LEAF);
- assert_string_equal(augments->child->next->next->next->next->next->next->name, "llist");
- assert_int_equal(augments->child->next->next->next->next->next->next->nodetype, LYS_LEAFLIST);
- assert_string_equal(augments->child->next->next->next->next->next->next->next->name, "list");
- assert_int_equal(augments->child->next->next->next->next->next->next->next->nodetype, LYS_LIST);
- assert_string_equal(augments->child->next->next->next->next->next->next->next->next->name, "uses");
- assert_int_equal(augments->child->next->next->next->next->next->next->next->next->nodetype, LYS_USES);
- assert_null(augments->child->next->next->next->next->next->next->next->next->next);
+ assert_string_equal(augments->child->next->next->name, "choice");
+ assert_int_equal(augments->child->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(((struct lysp_node_choice *)augments->child->next->next)->child->name, "case");
+ assert_int_equal(((struct lysp_node_choice *)augments->child->next->next)->child->nodetype, LYS_CASE);
+ assert_string_equal(augments->child->next->next->next->name, "subcont");
+ assert_int_equal(augments->child->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(augments->child->next->next->next->next->name, "leaf");
+ assert_int_equal(augments->child->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(augments->child->next->next->next->next->next->name, "llist");
+ assert_int_equal(augments->child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(augments->child->next->next->next->next->next->next->name, "list");
+ assert_int_equal(augments->child->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(augments->child->next->next->next->next->next->next->next->name, "uses");
+ assert_int_equal(augments->child->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(augments->child->next->next->next->next->next->next->next->next);
assert_string_equal(augments->actions->name, "action");
assert_string_equal(augments->notifs->name, "notif");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(augments->exts[0]), LY_STMT_AUGMENT);
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)augments);
- augments = NULL;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &aug_meta, NULL, NULL), LY_SUCCESS);
- assert_string_equal(augments->nodeid, "target");
- lysp_node_free(UTEST_LYCTX, (struct lysp_node *)augments);
- augments = NULL;
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(augments->exts[0]), LY_STMT_AUGMENT, "MY_MTU");
+
+ /* min subelems */
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ augments = mod->parsed->augments;
+ assert_string_equal(augments->nodeid, "/a2:target");
}
static void
test_deviate_elem(void **state)
{
- const char *data;
- struct lysp_deviate *deviates = NULL;
+ const char *yin_data;
/* invalid arguments */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &deviates, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"dev-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"\" of \"value\" attribute in \"deviate\" element. "
"Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\".", NULL, 1);
- deviates = NULL;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &deviates, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"dev-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"invalid\" of \"value\" attribute in \"deviate\" element. "
"Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\".", NULL, 1);
- deviates = NULL;
-
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &deviates, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"dev-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"ad\" of \"value\" attribute in \"deviate\" element. "
"Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\".", NULL, 1);
- deviates = NULL;
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &deviates, NULL, NULL), LY_EVALID);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"dev-mod\" failed.", NULL, 0);
CHECK_LOG_CTX("Invalid value \"adds\" of \"value\" attribute in \"deviate\" element. "
"Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\".", NULL, 1);
- deviates = NULL;
-
- data = ELEMENT_WRAPPER_START
- "\n"
- " \n"
- ""
- ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &deviates, NULL, NULL), LY_EVALID);
- CHECK_LOG_CTX("Deviate of this type doesn't allow \"must\" as it's sub-element.", NULL, 2);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"dev-mod\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Deviate of this type doesn't allow \"must\" as it's sub-element.", NULL, 1);
}
static void
test_deviation_elem(void **state)
{
- const char *data;
- struct lysp_deviation *deviations = NULL;
+ const char *yin_data;
/* invalid */
- data = ELEMENT_WRAPPER_START "" ELEMENT_WRAPPER_END;
- assert_int_equal(test_element_helper(state, data, &deviations, NULL, NULL), LY_EVALID);
- CHECK_LOG_CTX("Missing mandatory sub-element \"deviate\" of \"deviation\" element.", NULL, 1);
-}
-
-static struct lysp_module *
-mod_renew(struct lysp_yin_ctx *ctx)
-{
- struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
- struct lysp_module *pmod;
-
- lys_module_free(ly_ctx, PARSER_CUR_PMOD(ctx)->mod, 0);
- pmod = calloc(1, sizeof *pmod);
- ctx->parsed_mods->objs[0] = pmod;
- pmod->mod = calloc(1, sizeof *pmod->mod);
- pmod->mod->parsed = pmod;
- pmod->mod->ctx = ly_ctx;
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
- return pmod;
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"dev\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Missing mandatory sub-element \"deviate\" of \"deviation\" element.", NULL, 1);
}
static void
test_module_elem(void **state)
{
- const char *data;
- struct lysp_module *lysp_mod = mod_renew(YCTX);
+ const char *yin_data;
+ struct lys_module *mod = NULL;
+ struct lysp_module *lysp_mod = NULL;
+ const char *a_mod =
+ ""
+ " "
+ " "
+ "";
+ char *b_mod =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, a_mod, LYS_IN_YIN, NULL));
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, b_mod);
/* max subelems */
- data = "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " org\n"
- " contact\n"
- " desc\n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- EXT_SUBELEM "\n"
- "
\n";
- assert_int_equal(ly_in_new_memory(data, &UTEST_IN), LY_SUCCESS);
- assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " org"
+ " contact"
+ " desc"
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " " EXT_SUBELEM ""
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ lysp_mod = mod->parsed;
- assert_int_equal(yin_parse_mod(YCTX, lysp_mod), LY_SUCCESS);
assert_string_equal(lysp_mod->mod->name, "mod");
assert_string_equal(lysp_mod->revs[0].date, "2019-02-02");
assert_string_equal(lysp_mod->mod->ns, "ns");
@@ -3101,14 +3431,13 @@ test_module_elem(void **state)
assert_string_equal(lysp_mod->mod->dsc, "desc");
assert_string_equal(lysp_mod->mod->ref, "ref");
assert_int_equal(lysp_mod->version, LYS_VERSION_1_1);
- CHECK_LYSP_IMPORT(lysp_mod->imports, NULL, 0, "a-mod",
- "imp-pref", NULL, "");
+ CHECK_LYSP_IMPORT(lysp_mod->imports, NULL, 0, "a-mod", "imp-pref", NULL, "");
assert_string_equal(lysp_mod->includes->name, "b-mod");
- assert_string_equal(lysp_mod->extensions->name, "ext");
+ assert_string_equal(lysp_mod->extensions->name, "c-define");
assert_string_equal(lysp_mod->features->name, "feature");
assert_string_equal(lysp_mod->identities->name, "ident-name");
assert_string_equal(lysp_mod->typedefs->name, "tpdf");
- assert_string_equal(lysp_mod->groupings->name, "grp");
+ assert_string_equal(lysp_mod->groupings->name, "uses-name");
assert_string_equal(lysp_mod->data->name, "anyd");
assert_int_equal(lysp_mod->data->nodetype, LYS_ANYDATA);
assert_string_equal(lysp_mod->data->next->name, "anyx");
@@ -3126,105 +3455,102 @@ test_module_elem(void **state)
assert_string_equal(lysp_mod->data->next->next->next->next->next->next->next->name, "uses-name");
assert_int_equal(lysp_mod->data->next->next->next->next->next->next->next->nodetype, LYS_USES);
assert_null(lysp_mod->data->next->next->next->next->next->next->next->next);
- assert_string_equal(lysp_mod->augments->nodeid, "target");
+ assert_string_equal(lysp_mod->augments->nodeid, "/pref:cont");
assert_string_equal(lysp_mod->rpcs->name, "rpc-name");
assert_string_equal(lysp_mod->notifs->name, "notf");
- assert_string_equal(lysp_mod->deviations->nodeid, "target");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(lysp_mod->exts[0]), LY_STMT_MODULE);
+ assert_string_equal(lysp_mod->deviations->nodeid, "/pref:cont");
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(lysp_mod->exts[0]), LY_STMT_MODULE, "MY_MTU");
/* min subelems */
- ly_in_free(UTEST_IN, 0);
- lyxml_ctx_free(YCTX->xmlctx);
- lysp_mod = mod_renew(YCTX);
- data = "\n"
- " \n"
- " \n"
- " \n"
- "";
- assert_int_equal(ly_in_new_memory(data, &UTEST_IN), LY_SUCCESS);
- assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS);
- assert_int_equal(yin_parse_mod(YCTX, lysp_mod), LY_SUCCESS);
- assert_string_equal(lysp_mod->mod->name, "mod");
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ lysp_mod = mod->parsed;
+ assert_string_equal(lysp_mod->mod->name, "mod-min");
/* incorrect subelem order */
- ly_in_free(UTEST_IN, 0);
- lyxml_ctx_free(YCTX->xmlctx);
- lysp_mod = mod_renew(YCTX);
- data = "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- "";
- assert_int_equal(ly_in_new_memory(data, &UTEST_IN), LY_SUCCESS);
- assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS);
- assert_int_equal(yin_parse_mod(YCTX, lysp_mod), LY_EVALID);
- CHECK_LOG_CTX("Invalid order of module\'s sub-elements \"namespace\" can\'t appear after \"feature\".", NULL, 3);
-}
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ "";
-static struct lysp_submodule *
-submod_renew(struct lysp_yin_ctx *ctx, const char *belongs_to)
-{
- struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
- struct lysp_submodule *submod;
-
- lys_module_free(ly_ctx, PARSER_CUR_PMOD(ctx)->mod, 0);
- submod = calloc(1, sizeof *submod);
- ctx->parsed_mods->objs[0] = submod;
- submod->mod = calloc(1, sizeof *submod->mod);
- lysdict_insert(ly_ctx, belongs_to, 0, &submod->mod->name);
- submod->mod->parsed = (struct lysp_module *)submod;
- submod->mod->ctx = ly_ctx;
-
- return submod;
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"mod-inv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid order of module\'s sub-elements \"namespace\" can\'t appear after \"feature\".", NULL, 1);
}
static void
test_submodule_elem(void **state)
{
- const char *data;
- struct lysp_submodule *lysp_submod = submod_renew(YCTX, "module-name");
+ char *yin_data;
+ const char *parent_data;
+ struct lys_module *mod = NULL;
+ struct lysp_submodule *lysp_submod = NULL;
+ const char *a_mod =
+ ""
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, a_mod, LYS_IN_YIN, NULL));
/* max subelements */
- data = "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " org\n"
- " contact\n"
- " desc\n"
- " ref\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- EXT_SUBELEM "\n"
- "
\n";
- assert_int_equal(ly_in_new_memory(data, &UTEST_IN), LY_SUCCESS);
- assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS);
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " org"
+ " contact"
+ " desc"
+ " ref"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "
"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " " EXT_SUBELEM ""
+ "";
+
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, yin_data);
+ parent_data =
+ ""
+ " "
+ " "
+ " "
+ "";
- assert_int_equal(yin_parse_submod(YCTX, lysp_submod), LY_SUCCESS);
- CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (mod) are not necessary.",
- NULL, 0);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, parent_data, LYS_IN_YIN, &mod));
+ lysp_submod = mod->parsed->includes[0].submodule;
assert_string_equal(lysp_submod->name, "mod");
assert_string_equal(lysp_submod->revs[0].date, "2019-02-02");
assert_string_equal(lysp_submod->prefix, "pref");
@@ -3234,9 +3560,7 @@ test_submodule_elem(void **state)
assert_string_equal(lysp_submod->dsc, "desc");
assert_string_equal(lysp_submod->ref, "ref");
assert_int_equal(lysp_submod->version, LYS_VERSION_1_1);
- CHECK_LYSP_IMPORT(lysp_submod->imports, NULL, 0, "a-mod",
- "imp-pref", NULL, "");
- assert_string_equal(lysp_submod->includes->name, "b-mod");
+ CHECK_LYSP_IMPORT(lysp_submod->imports, NULL, 0, "a-mod", "imp-pref", NULL, "");
assert_string_equal(lysp_submod->extensions->name, "ext");
assert_string_equal(lysp_submod->features->name, "feature");
assert_string_equal(lysp_submod->identities->name, "ident-name");
@@ -3259,254 +3583,239 @@ test_submodule_elem(void **state)
assert_string_equal(lysp_submod->data->next->next->next->next->next->next->next->name, "uses-name");
assert_int_equal(lysp_submod->data->next->next->next->next->next->next->next->nodetype, LYS_USES);
assert_null(lysp_submod->data->next->next->next->next->next->next->next->next);
- assert_string_equal(lysp_submod->augments->nodeid, "target");
+ assert_string_equal(lysp_submod->augments->nodeid, "/pref:cont");
assert_string_equal(lysp_submod->rpcs->name, "rpc-name");
assert_string_equal(lysp_submod->notifs->name, "notf");
- assert_string_equal(lysp_submod->deviations->nodeid, "target");
- TEST_1_CHECK_LYSP_EXT_INSTANCE(&(lysp_submod->exts[0]), LY_STMT_SUBMODULE);
-
- /* min subelemnts */
- ly_in_free(UTEST_IN, 0);
- lyxml_ctx_free(YCTX->xmlctx);
- lysp_submod = submod_renew(YCTX, "module-name");
- data = "\n"
- " \n"
- " \n"
+ assert_string_equal(lysp_submod->deviations->nodeid, "/pref:cont");
+ TEST_1_CHECK_LYSP_EXT_INSTANCE(&(lysp_submod->exts[0]), LY_STMT_SUBMODULE, "MY_MTU");
+
+ /* min subelements */
+ yin_data =
+ ""
+ " "
+ " "
"";
- assert_int_equal(ly_in_new_memory(data, &UTEST_IN), LY_SUCCESS);
- assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS);
- assert_int_equal(yin_parse_submod(YCTX, lysp_submod), LY_SUCCESS);
+
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, yin_data);
+
+ parent_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, parent_data, LYS_IN_YIN, &mod));
+ lysp_submod = mod->parsed->includes[0].submodule;
+
assert_string_equal(lysp_submod->prefix, "pref");
assert_int_equal(lysp_submod->version, LYS_VERSION_1_0);
/* incorrect subelem order */
- ly_in_free(UTEST_IN, 0);
- lyxml_ctx_free(YCTX->xmlctx);
- lysp_submod = submod_renew(YCTX, "module-name");
- data = "\n"
- " \n"
- " ref\n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " ref"
+ " "
"";
- assert_int_equal(ly_in_new_memory(data, &UTEST_IN), LY_SUCCESS);
- assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS);
- assert_int_equal(yin_parse_submod(YCTX, lysp_submod), LY_EVALID);
- CHECK_LOG_CTX("Invalid order of submodule's sub-elements \"belongs-to\" can't appear after \"reference\".", NULL, 4);
+
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)yin_data);
+
+ parent_data =
+ ""
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, parent_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"parent3\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"submod-inv\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Invalid order of submodule's sub-elements \"belongs-to\" can't appear after \"reference\".", NULL, 1);
}
static void
test_yin_parse_module(void **state)
{
- const char *data;
- struct lys_module *mod;
- struct lysp_yin_ctx *yin_ctx = NULL;
- struct ly_in *in = NULL;
-
- mod = calloc(1, sizeof *mod);
- mod->ctx = UTEST_LYCTX;
- data = " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " test\n"
- " \n"
- " \n"
- " test\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- "\n";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_module(&yin_ctx, in, mod), LY_SUCCESS);
- assert_null(mod->parsed->exts->child->next->child);
- assert_string_equal(mod->parsed->exts->child->next->arg, "test");
- lys_module_free(UTEST_LYCTX, mod, 0);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- mod = NULL;
- yin_ctx = NULL;
-
- mod = calloc(1, sizeof *mod);
- mod->ctx = UTEST_LYCTX;
- data = ""
+ " "
+ " "
+ " "
+ "";
+
+ yin_data =
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " test"
+ " "
+ " "
+ " test"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
+ assert_null(mod->parsed->exts[0].child->next->child);
+ assert_string_equal(mod->parsed->exts[0].child->next->arg, "test");
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, ext_mod, LYS_IN_YIN, NULL));
+
+ yin_data =
+ "\n"
+ " xmlns:myext=\"urn:example:extensions\">"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " The MTU of the interface."
+ " "
+ " "
+ " "
+ "
"
+ "";
- " \n"
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
- " \n"
- " \n"
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ "";
- " \n"
- " \n"
- " \n"
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, &mod));
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " The MTU of the interface.\n"
- " \n"
- " \n"
- " \n"
- "
\n"
- "\n";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_module(&yin_ctx, in, mod), LY_SUCCESS);
- lys_module_free(UTEST_LYCTX, mod, 0);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- mod = NULL;
- yin_ctx = NULL;
-
- mod = calloc(1, sizeof *mod);
- mod->ctx = UTEST_LYCTX;
- data = "\n"
- " \n"
- " \n"
- " \n"
- "\n";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_module(&yin_ctx, in, mod), LY_SUCCESS);
- lys_module_free(UTEST_LYCTX, mod, 0);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- mod = NULL;
- yin_ctx = NULL;
-
- mod = calloc(1, sizeof *mod);
- mod->ctx = UTEST_LYCTX;
- data = ""
- "\n";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_module(&yin_ctx, in, mod), LY_EINVAL);
+ yin_data = "";
+
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0);
- lys_module_free(UTEST_LYCTX, mod, 0);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
-
- mod = calloc(1, sizeof *mod);
- mod->ctx = UTEST_LYCTX;
- data = "\n"
- " \n"
- " \n"
- " \n"
- "\n"
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ ""
"";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_module(&yin_ctx, in, mod), LY_EVALID);
- CHECK_LOG_CTX("Trailing garbage \"\" after module, expected end-of-input.", NULL, 6);
- lys_module_free(UTEST_LYCTX, mod, 0);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- mod = NULL;
- yin_ctx = NULL;
+
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, yin_data, LYS_IN_YIN, NULL));
+ CHECK_LOG_CTX("Parsing module \"example-foo-garb\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Trailing garbage \"\" after module, expected end-of-input.", NULL, 1);
}
static void
test_yin_parse_submodule(void **state)
{
- const char *data;
- struct lysp_yin_ctx *yin_ctx = NULL;
- struct lysp_submodule *submod = NULL;
- struct ly_in *in;
-
- lysdict_insert(UTEST_LYCTX, "a", 0, &PARSER_CUR_PMOD(YCTX)->mod->name);
+ struct lys_module *mod;
+ char *yin_data;
+ const char *mod_a =
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
- data = "\n"
+ yin_data =
"\n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
- " \n"
+ " xmlns:a=\"urn:a\">"
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
"";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_submodule(&yin_ctx, UTEST_LYCTX, (struct lysp_ctx *)YCTX, in, &submod), LY_SUCCESS);
- lysp_module_free(UTEST_LYCTX, (struct lysp_module *)submod);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- yin_ctx = NULL;
- submod = NULL;
-
- data = "\n"
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, yin_data);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, mod_a, LYS_IN_YIN, &mod));
+ UTEST_TEARDOWN;
+ UTEST_SETUP;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
"";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_submodule(&yin_ctx, UTEST_LYCTX, (struct lysp_ctx *)YCTX, in, &submod), LY_SUCCESS);
- lysp_module_free(UTEST_LYCTX, (struct lysp_module *)submod);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- yin_ctx = NULL;
- submod = NULL;
-
- data = "\n"
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, yin_data);
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, mod_a, LYS_IN_YIN, &mod));
+ UTEST_TEARDOWN;
+ UTEST_SETUP;
+
+ yin_data =
""
"";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_submodule(&yin_ctx, UTEST_LYCTX, (struct lysp_ctx *)YCTX, in, &submod), LY_EINVAL);
+ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, yin_data);
+ assert_int_equal(lys_parse_mem(UTEST_LYCTX, mod_a, LYS_IN_YIN, &mod), LY_EINVAL);
+ CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, 0);
+ CHECK_LOG_CTX("Parsing submodule \"asub\" failed.", NULL, 0);
CHECK_LOG_CTX("Input data contains module when a submodule is expected.", NULL, 0);
- lysp_module_free(UTEST_LYCTX, (struct lysp_module *)submod);
- lysp_yin_ctx_free(yin_ctx);
- ly_in_free(in, 0);
- yin_ctx = NULL;
- submod = NULL;
-
- data = "\n"
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
- "\n"
- "\n"
- " \n"
- " \n"
- " \n"
- " \n"
+
+ UTEST_TEARDOWN;
+ UTEST_SETUP;
+
+ yin_data =
+ ""
+ " "
+ " "
+ " "
+ " "
+ ""
+ ""
+ " "
+ " "
+ " "
+ " "
"";
- assert_int_equal(ly_in_new_memory(data, &in), LY_SUCCESS);
- assert_int_equal(yin_parse_submodule(&yin_ctx, UTEST_LYCTX, (struct lysp_ctx *)YCTX, in, &submod), LY_EVALID);
- CHECK_LOG_CTX("Trailing garbage \"" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -51,7 +53,7 @@ test_plugin_store(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value value = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type, *lysc_type2;
LY_ERR ly_ret;
const char *schema;
@@ -61,6 +63,7 @@ test_plugin_store(void **state)
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
lysc_type2 = ((struct lysc_node_leaf *)mod->compiled->data->next)->type;
+ type = lysc_get_type_plugin(lysc_type2->plugin_ref);
/* check proper type */
assert_string_equal("ly2 binary", type->id);
@@ -250,13 +253,14 @@ test_plugin_print(void **state)
struct lyd_value value = {0};
struct lys_module *mod;
struct lysc_type *lysc_type;
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]));
+ struct lyplg_type *type = NULL;
struct ly_err_item *err = NULL;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a", "leaf l {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* Testing empty value. */
val = "";
@@ -273,13 +277,14 @@ test_plugin_duplicate(void **state)
struct lyd_value value = {0}, dup;
struct lys_module *mod;
struct lysc_type *lysc_type;
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]));
+ struct lyplg_type *type = NULL;
struct ly_err_item *err = NULL;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a", "leaf l {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* Testing empty value. */
val = "";
@@ -298,7 +303,7 @@ test_plugin_sort(void **state)
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
@@ -306,6 +311,7 @@ test_plugin_sort(void **state)
schema = MODULE_CREATE_YANG("a", "leaf-list ll {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* v1 < v2, v2 > v1, v1 == v1 */
v1 = "YWhveQ=="; /* ahoy */
diff --git a/tests/utests/types/bits.c b/tests/utests/types/bits.c
index d599e3c8b8..cd610e6fd7 100644
--- a/tests/utests/types/bits.c
+++ b/tests/utests/types/bits.c
@@ -21,7 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"\n" \
@@ -67,10 +66,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -800,7 +801,7 @@ test_plugin_store(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value value = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
char *alloc;
@@ -811,6 +812,7 @@ test_plugin_store(void **state)
" bit two; bit three;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* check proper type */
assert_string_equal("ly2 bits", type->id);
@@ -884,7 +886,7 @@ test_plugin_compare(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
const char *schema;
@@ -904,6 +906,7 @@ test_plugin_compare(void **state)
"leaf p4 {type string;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
for (unsigned int it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) {
@@ -946,7 +949,7 @@ test_plugin_sort(void **state)
{
const char *schema;
struct lys_module *mod;
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
struct lyd_value val1 = {0}, val2 = {0};
@@ -954,6 +957,7 @@ test_plugin_sort(void **state)
schema = MODULE_CREATE_YANG("T0", "leaf-list ll { type bits { bit zero; bit one; bit two; bit three;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* 1000 < 1001 */
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, "three", strlen("three") * 8,
@@ -983,7 +987,7 @@ test_plugin_print(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
const char *schema;
@@ -996,6 +1000,7 @@ test_plugin_print(void **state)
" bit two; bit three;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
for (unsigned int it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) {
@@ -1025,7 +1030,7 @@ test_plugin_dup(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
const char *schema;
LY_ERR ly_ret;
@@ -1038,6 +1043,7 @@ test_plugin_dup(void **state)
" bit two; bit three;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
for (unsigned int it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) {
diff --git a/tests/utests/types/boolean.c b/tests/utests/types/boolean.c
index 645de9a442..d86d456846 100644
--- a/tests/utests/types/boolean.c
+++ b/tests/utests/types/boolean.c
@@ -49,10 +49,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
diff --git a/tests/utests/types/decimal64.c b/tests/utests/types/decimal64.c
index ca9bc8934b..81833c4091 100644
--- a/tests/utests/types/decimal64.c
+++ b/tests/utests/types/decimal64.c
@@ -49,10 +49,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
diff --git a/tests/utests/types/empty.c b/tests/utests/types/empty.c
index a7953b77d3..38eb56fc76 100644
--- a/tests/utests/types/empty.c
+++ b/tests/utests/types/empty.c
@@ -49,10 +49,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
diff --git a/tests/utests/types/enumeration.c b/tests/utests/types/enumeration.c
index 119ebfd768..89bd666c00 100644
--- a/tests/utests/types/enumeration.c
+++ b/tests/utests/types/enumeration.c
@@ -49,10 +49,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -94,13 +96,14 @@ test_plugin_sort(void **state)
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_ENUM]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
schema = MODULE_CREATE_YANG("sort", "leaf l1 {type enumeration {enum white; enum yellow; enum black;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "white";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
diff --git a/tests/utests/types/identityref.c b/tests/utests/types/identityref.c
index b038f96e40..a62fbd4b44 100644
--- a/tests/utests/types/identityref.c
+++ b/tests/utests/types/identityref.c
@@ -40,10 +40,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
diff --git a/tests/utests/types/inet_types.c b/tests/utests/types/inet_types.c
index 8e2e7942d5..bbe3c05e79 100644
--- a/tests/utests/types/inet_types.c
+++ b/tests/utests/types/inet_types.c
@@ -81,10 +81,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -197,7 +199,7 @@ test_plugin_sort(void **state)
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
@@ -212,6 +214,7 @@ test_plugin_sort(void **state)
/* ipv4-address */
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "192.168.0.1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
@@ -239,7 +242,7 @@ test_plugin_sort(void **state)
/* ipv6-address */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next)->type;
- type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]));
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "2008:15:0:0:0:0:feAC:1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
@@ -267,7 +270,7 @@ test_plugin_sort(void **state)
/* ipv4-address-no-zone */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next)->type;
- type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]));
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "127.0.0.1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
@@ -282,7 +285,7 @@ test_plugin_sort(void **state)
/* ipv6-address-no-zone */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next)->type;
- type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]));
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "A:B:c:D:e:f:1:1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
@@ -297,6 +300,7 @@ test_plugin_sort(void **state)
/* ipv4-prefix */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next->next)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "0.1.58.4/32";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
@@ -311,10 +315,11 @@ test_plugin_sort(void **state)
/* ipv6-prefix */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next->next->next)->type;
- v1 = "::C:D:E:f:a/96";
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
+ v1 = "::C:D:E:f:a/112";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
- v2 = "::C:D:E:f:a/112";
+ v2 = "::C:D:E:f:a/96";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2) * 8,
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
diff --git a/tests/utests/types/instanceid.c b/tests/utests/types/instanceid.c
index b3f6a5c45a..02e9b9fe5e 100644
--- a/tests/utests/types/instanceid.c
+++ b/tests/utests/types/instanceid.c
@@ -18,7 +18,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
@@ -48,13 +47,15 @@
#define LYB_CHECK_START \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
- char *xml_out, *data;
+ char *xml_out, *data; \
+ uint32_t xml_len;
#define LYB_CHECK_END \
{ \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -79,12 +80,12 @@ static void
test_data_xml(void **state)
{
const char *schema, *schema2;
- const enum ly_path_pred_type val1[] = {0, 0};
- const enum ly_path_pred_type val2[] = {LY_PATH_PREDTYPE_LIST, 0};
- const enum ly_path_pred_type val3[] = {LY_PATH_PREDTYPE_LEAFLIST};
- const enum ly_path_pred_type val4[] = {LY_PATH_PREDTYPE_LIST, 0};
- const enum ly_path_pred_type val5[] = {LY_PATH_PREDTYPE_LIST, 0};
- const enum ly_path_pred_type val6[] = {LY_PATH_PREDTYPE_LIST, 0};
+ const int val1[] = {0, 0};
+ const int val2[] = {0, 0};
+ const int val3[] = {0};
+ const int val4[] = {0, 0};
+ const int val5[] = {0, 0};
+ const int val6[] = {0, 0};
/* xml test */
schema = MODULE_CREATE_YANG("mod", "container cont {leaf l2 {type empty;}}");
diff --git a/tests/utests/types/int16.c b/tests/utests/types/int16.c
index 96828e0330..efff7f8f54 100644
--- a/tests/utests/types/int16.c
+++ b/tests/utests/types/int16.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/int32.c b/tests/utests/types/int32.c
index fa2b34107e..7e03f9375a 100644
--- a/tests/utests/types/int32.c
+++ b/tests/utests/types/int32.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/int64.c b/tests/utests/types/int64.c
index 04066739e7..ca0de307d8 100644
--- a/tests/utests/types/int64.c
+++ b/tests/utests/types/int64.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/int8.c b/tests/utests/types/int8.c
index 62ae3ff868..294e0354e4 100644
--- a/tests/utests/types/int8.c
+++ b/tests/utests/types/int8.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define LYD_TREE_CREATE(INPUT, MODEL) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL)
@@ -71,10 +69,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -1399,7 +1399,7 @@ test_plugin_store(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value value = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
char *alloc;
@@ -1410,6 +1410,7 @@ test_plugin_store(void **state)
schema = MODULE_CREATE_YANG("defs", "leaf port {type int8 {range \"-50 .. 50\";}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* check proper type */
assert_string_equal("ly2 integers", type->id);
@@ -1546,7 +1547,7 @@ test_plugin_compare(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
const char *schema;
@@ -1565,6 +1566,7 @@ test_plugin_compare(void **state)
"leaf p4 {type uint8;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
for (unsigned int it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) {
@@ -1631,7 +1633,7 @@ test_plugin_print(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
const char *schema;
@@ -1642,6 +1644,7 @@ test_plugin_print(void **state)
schema = MODULE_CREATE_YANG("defs", "leaf port {type int8;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
for (unsigned int it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) {
@@ -1671,7 +1674,7 @@ test_plugin_dup(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type[2];
const char *schema;
LY_ERR ly_ret;
@@ -1682,6 +1685,7 @@ test_plugin_dup(void **state)
schema = MODULE_CREATE_YANG("T0", "leaf port {type int8;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type[0] = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type[0]->plugin_ref);
schema = MODULE_CREATE_YANG("T1",
"typedef my_int_type {"
diff --git a/tests/utests/types/leafref.c b/tests/utests/types/leafref.c
index 6c464ceb94..1fe9fe08cf 100644
--- a/tests/utests/types/leafref.c
+++ b/tests/utests/types/leafref.c
@@ -49,11 +49,13 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME1 " xmlns=\"urn:tests:" MOD_NAME "\">" DATA1 "" NODE_NAME1 ">" \
"<" NODE_NAME2 " xmlns=\"urn:tests:" MOD_NAME "\">" DATA2 "" NODE_NAME2 ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -216,7 +218,7 @@ test_plugin_sort(void **state)
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_LEAFREF]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
@@ -232,6 +234,7 @@ test_plugin_sort(void **state)
"}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "str1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
diff --git a/tests/utests/types/string.c b/tests/utests/types/string.c
index 23210a70cd..50c0199b9e 100644
--- a/tests/utests/types/string.c
+++ b/tests/utests/types/string.c
@@ -20,8 +20,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"\n" \
@@ -67,10 +65,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -1122,7 +1122,7 @@ test_plugin_store(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value value = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
char *alloc_text;
unsigned int alloc_text_size;
@@ -1133,6 +1133,7 @@ test_plugin_store(void **state)
"pattern '[0-9\\n<>\\\"\\|]*' ;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *) mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* check proper type */
assert_string_equal("ly2 string", type->id);
@@ -1263,7 +1264,7 @@ test_plugin_compare(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
const char *schema;
@@ -1281,6 +1282,7 @@ test_plugin_compare(void **state)
"leaf p4 {type uint8;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *) mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
const char *val_init[] = {"hi", "hello", "hi", "hello", "hell", "hh"};
@@ -1321,7 +1323,7 @@ test_plugin_print(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
LY_ERR ly_ret;
@@ -1330,6 +1332,7 @@ test_plugin_print(void **state)
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *) mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* CREATE VALUES */
const char *val_init[] = {"20", "0x4A", "<|>", "\""};
@@ -1360,7 +1363,7 @@ test_plugin_dup(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value values[10];
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type[2];
const char *schema;
LY_ERR ly_ret;
@@ -1377,6 +1380,7 @@ test_plugin_dup(void **state)
"leaf port {type my_int_type; }");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type[1] = ((struct lysc_node_leaf *) mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type[1]->plugin_ref);
/* CREATE VALUES */
const char *val_init[] = {"20", "0x4A", "<\">", "0x4A"};
diff --git a/tests/utests/types/uint16.c b/tests/utests/types/uint16.c
index 2ded9eb596..cb4bb397c6 100644
--- a/tests/utests/types/uint16.c
+++ b/tests/utests/types/uint16.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/uint32.c b/tests/utests/types/uint32.c
index 89221c404f..a547b2a6ef 100644
--- a/tests/utests/types/uint32.c
+++ b/tests/utests/types/uint32.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/uint64.c b/tests/utests/types/uint64.c
index 71e024e09a..9feadf23b2 100644
--- a/tests/utests/types/uint64.c
+++ b/tests/utests/types/uint64.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/uint8.c b/tests/utests/types/uint8.c
index 618e422744..79dd852dae 100644
--- a/tests/utests/types/uint8.c
+++ b/tests/utests/types/uint8.c
@@ -21,8 +21,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
-#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
diff --git a/tests/utests/types/union.c b/tests/utests/types/union.c
index 9091b632ef..890363e19a 100644
--- a/tests/utests/types/union.c
+++ b/tests/utests/types/union.c
@@ -18,7 +18,6 @@
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
-#include "path.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
@@ -50,10 +49,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -65,7 +66,7 @@ static void
test_data_xml(void **state)
{
const char *schema;
- const enum ly_path_pred_type val1[] = {LY_PATH_PREDTYPE_LEAFLIST};
+ const int val1[] = {0};
/* xml test */
schema = MODULE_CREATE_YANG("defs", "identity ident1; identity ident2 {base ident1;}"
@@ -154,13 +155,14 @@ test_plugin_sort(void **state)
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
schema = MODULE_CREATE_YANG("sort", "leaf-list ll {type union {type uint16; type int16;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
v1 = "1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1) * 8,
@@ -192,6 +194,7 @@ test_validation(void **state)
const char *schema, *data;
struct lyd_node *tree;
char *out;
+ uint32_t out_len;
schema = MODULE_CREATE_YANG("val",
"leaf l1 {\n"
@@ -216,9 +219,10 @@ test_validation(void **state)
/* parse from LYB */
data = "auto1515";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_int_equal(LY_SUCCESS,
+ utest_lyd_print_mem_len(&out, &out_len, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
lyd_free_all(tree);
- CHECK_PARSE_LYD_PARAM(out, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+ CHECK_PARSE_LYD_PARAM_LEN(out, out_len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
free(out);
/* validate */
@@ -273,18 +277,20 @@ test_validation(void **state)
/* parse from LYB #1 */
data = "2test2";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_int_equal(LY_SUCCESS,
+ utest_lyd_print_mem_len(&out, &out_len, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
lyd_free_all(tree);
- CHECK_PARSE_LYD_PARAM(out, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+ CHECK_PARSE_LYD_PARAM_LEN(out, out_len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
free(out);
lyd_free_all(tree);
/* parse from LYB #2 */
data = "onetestone";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
+ assert_int_equal(LY_SUCCESS,
+ utest_lyd_print_mem_len(&out, &out_len, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS));
lyd_free_all(tree);
- CHECK_PARSE_LYD_PARAM(out, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+ CHECK_PARSE_LYD_PARAM_LEN(out, out_len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
free(out);
/* remove the target and create another, which is represented the same way in LYB */
@@ -306,7 +312,7 @@ test_validation_store_only(void **state)
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value value = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
const char *schema;
@@ -323,6 +329,7 @@ test_validation_store_only(void **state)
"}\n");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* check proper type */
assert_string_equal("ly2 union", type->id);
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index 9b1f841e9a..86206f47a8 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -18,7 +18,6 @@
#include
-#include "compat.h"
#include "libyang.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
@@ -65,10 +64,12 @@
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
+ uint32_t xml_len; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
- assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
+ assert_int_equal(utest_lyd_print_mem_len(&xml_out, &xml_len, tree_1, LYD_LYB, LYD_PRINT_SIBLINGS), 0); \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, xml_out, xml_len, LYD_LYB, \
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
@@ -281,7 +282,7 @@ test_sort(void **state)
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
- struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "ietf-yang-types", "2025-12-22", "date-and-time"));
+ struct lyplg_type *type = NULL;
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
@@ -290,6 +291,7 @@ test_sort(void **state)
"leaf-list ll {type yang:date-and-time;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
+ type = lysc_get_type_plugin(lysc_type->plugin_ref);
/* v1 > v2, v2 < v1, v1 == v1 */
v1 = "2005-05-25T23:15:15Z";
diff --git a/tests/utests/utests.h b/tests/utests/utests.h
index aaf3701e6a..a2dad5d20d 100644
--- a/tests/utests/utests.h
+++ b/tests/utests/utests.h
@@ -29,12 +29,11 @@
#include
+#include "compat.h"
#include "libyang.h"
#include "plugins_exts/metadata.h"
-#include "plugins_internal.h"
#include "plugins_types.h"
#include "tests_config.h"
-#include "tree_schema_internal.h"
/**
* TESTS OVERVIEW
@@ -142,6 +141,55 @@ struct utest_context {
} \
}
+/**
+ * @brief Parse (and validate) bounded data from memory as a YANG data tree.
+ */
+#define CHECK_PARSE_LYD_PARAM_LEN(INPUT, INPUT_LEN, INPUT_FORMAT, PARSE_OPTIONS, VALIDATE_OPTIONS, RET, OUT_NODE) \
+ { \
+ LY_ERR _r = lyd_parse_data_mem_len(_UC->ctx, INPUT, INPUT_LEN, INPUT_FORMAT, PARSE_OPTIONS, VALIDATE_OPTIONS, \
+ &OUT_NODE); \
+ if (_r != RET) { \
+ if (_r) { \
+ fail_msg("%s != 0x%d; MSG: %s", #RET, _r, ly_err_last(_UC->ctx)->msg); \
+ } else { \
+ fail_msg("%s != 0x%d", #RET, _r); \
+ } \
+ } \
+ }
+
+/**
+ * @brief Print data into memory and return the exact binary-safe output length.
+ */
+static inline LY_ERR
+utest_lyd_print_mem_len(char **strp, uint32_t *len, const struct lyd_node *root, LYD_FORMAT format, uint32_t options)
+{
+ LY_ERR ret;
+ struct ly_out *out;
+ size_t printed;
+
+ *strp = NULL;
+ *len = 0;
+ ret = ly_out_new_memory(strp, 0, &out);
+ if (ret) {
+ return ret;
+ }
+
+ if (options & LYD_PRINT_SIBLINGS) {
+ ret = lyd_print_all(out, root, format, options & ~LYD_PRINT_SIBLINGS);
+ } else {
+ ret = lyd_print_tree(out, root, format, options);
+ }
+
+ printed = ly_out_printed(out);
+ ly_out_free(out, NULL, 0);
+ if (!ret && (printed > UINT32_MAX)) {
+ ret = LY_EINVAL;
+ } else if (!ret) {
+ *len = (uint32_t)printed;
+ }
+ return ret;
+}
+
/**
* @brief Check if lyd_node and his subnodes have correct values. Print lyd_node and his subnodes into a string in json or xml format.
* @param[in] NODE pointer to lyd_node
@@ -222,7 +270,7 @@ struct utest_context {
*/
/**
- * @brief check compileted type
+ * @brief check compiled type
*
* @param[in] NODE pointer to lysc_type value
* @param[in] TYPE expected type [LY_DATA_TYPE](@ref LY_DATA_TYPE)
@@ -232,7 +280,7 @@ struct utest_context {
assert_non_null(NODE); \
assert_int_equal((NODE)->basetype, TYPE); \
CHECK_ARRAY((NODE)->exts, EXTS); \
- assert_ptr_equal((NODE)->plugin_ref, lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[TYPE]))
+ assert_non_null(lysc_get_type_plugin((NODE)->plugin_ref))
/**
* @brief check compileted numeric type
@@ -585,9 +633,8 @@ struct utest_context {
* LYS_USES, LYS_INPUT, LYS_OUTPUT, LYS_GROUPING, LYS_AUGMENT
* @param[in] PARENT 0-> check if node is root, 1-> check if node is not root
* @param[in] REF expected reference statement
- * @param[in] WHEN 0-> pointer is null, 1 -> pointer is not null
*/
-#define CHECK_LYSP_NODE(NODE, DSC, EXTS, FLAGS, IFFEATURES, NAME, NEXT, NODETYPE, PARENT, REF, WHEN) \
+#define CHECK_LYSP_NODE(NODE, DSC, EXTS, FLAGS, IFFEATURES, NAME, NEXT, NODETYPE, PARENT, REF) \
assert_non_null(NODE); \
CHECK_STRING((NODE)->dsc, DSC); \
CHECK_ARRAY((NODE)->exts, EXTS); \
@@ -597,8 +644,7 @@ struct utest_context {
CHECK_POINTER((NODE)->next, NEXT); \
assert_int_equal((NODE)->nodetype, NODETYPE); \
CHECK_POINTER((NODE)->parent, PARENT); \
- CHECK_STRING((NODE)->ref, REF); \
- CHECK_POINTER(lysp_node_when((struct lysp_node *)NODE), WHEN);
+ CHECK_STRING((NODE)->ref, REF);
/**
* @brief assert that lysp_node structure members are correct
@@ -619,7 +665,8 @@ struct utest_context {
*/
#define CHECK_LYSP_NODE_LEAF(NODE, DSC, EXTS, FLAGS, IFFEATURES, NAME, NEXT, \
PARENT, REF, WHEN, MUSTS, UNITS, DFLT) \
- CHECK_LYSP_NODE(NODE, DSC, EXTS, FLAGS, IFFEATURES, NAME, NEXT, LYS_LEAF, PARENT, REF, WHEN); \
+ CHECK_LYSP_NODE(NODE, DSC, EXTS, FLAGS, IFFEATURES, NAME, NEXT, LYS_LEAF, PARENT, REF); \
+ CHECK_POINTER(((struct lysp_node_leaf *)NODE)->when, WHEN); \
CHECK_ARRAY((NODE)->musts, MUSTS); \
CHECK_STRING((NODE)->units, UNITS); \
CHECK_STRING((NODE)->dflt.str, DFLT);
@@ -1004,11 +1051,6 @@ struct utest_context {
{ \
LY_ARRAY_COUNT_TYPE arr_size = sizeof(VALUE) / sizeof(VALUE[0]); \
assert_int_equal(arr_size, LY_ARRAY_COUNT((NODE).target)); \
- for (LY_ARRAY_COUNT_TYPE it = 0; it < arr_size; it++) { \
- if ((NODE).target[it].predicates) { \
- assert_int_equal(VALUE[it], (NODE).target[it].predicates[0].type); \
- } \
- } \
}
/**
@@ -1347,9 +1389,14 @@ static int
utest_teardown(void **state)
{
*state = NULL;
+ const struct ly_err_item *err;
/* libyang context, no leftover messages */
- assert_null(ly_err_last(current_utest_context->ctx));
+ err = ly_err_last(current_utest_context->ctx);
+ if (err) {
+ fail_msg("Unexpected message in context: %s", err->msg);
+ }
+
ly_ctx_destroy(current_utest_context->ctx);
if (current_utest_context->orig_tz) {
diff --git a/tests/yanglint/data/test.sid b/tests/yanglint/data/test.sid
new file mode 100644
index 0000000000..19f38524f6
--- /dev/null
+++ b/tests/yanglint/data/test.sid
@@ -0,0 +1,40 @@
+{
+ "ietf-sid-file:sid-file": {
+ "module-name": "test-sid",
+ "module-revision": "2026-08-11",
+ "sid-file-status": "unpublished",
+ "description": "Generated by libyang 5.6.12, at 2026-08-17 08:37:22",
+ "assignment-range": [
+ {
+ "entry-point": "1000",
+ "size": "20"
+ }
+ ],
+ "item": [
+ {
+ "namespace": "module",
+ "identifier": "test-sid",
+ "status": "unstable",
+ "sid": "1000"
+ },
+ {
+ "namespace": "data",
+ "identifier": "/test-sid:test-container",
+ "status": "unstable",
+ "sid": "1001"
+ },
+ {
+ "namespace": "data",
+ "identifier": "/test-sid:test-container/test-leaf1",
+ "status": "unstable",
+ "sid": "1002"
+ },
+ {
+ "namespace": "data",
+ "identifier": "/test-sid:test-container/test-leaf2",
+ "status": "unstable",
+ "sid": "1003"
+ }
+ ]
+ }
+}
diff --git a/tests/yanglint/interactive/sample-skeleton.test b/tests/yanglint/interactive/sample-skeleton.test
new file mode 100644
index 0000000000..6968f8a22e
--- /dev/null
+++ b/tests/yanglint/interactive/sample-skeleton.test
@@ -0,0 +1,96 @@
+source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}]
+
+test print_yang {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ ly_cmd "load modleaf"
+ ly_cmd "print -f yang modleaf" "leaf lfl"
+}}
+
+test skeleton_generate_xml {Test generating xml skeleton to stdout and to file} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*true}
+ append pattern {.*-100}
+ append pattern {.*9999999999}
+ append pattern {.*hello}
+ append pattern {.*}
+ append pattern {.*10}
+ append pattern {.*20}
+ append pattern {.*}
+ append pattern {.*default-choice-val}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*augmented-value}
+ append pattern {.*1}
+ append pattern {.*2}
+ append pattern {.*}
+ append pattern ".*"
+
+ ly_cmd "load skeleton"
+ ly_cmd "load skeleton-augment"
+ ly_cmd "sample -f xml skeleton" $pattern
+
+ ly_cmd "sample -f xml -o test_output.xml skeleton"
+
+ if {![file exists "test_output.xml"]} {
+ error "Test failed: yanglint did not create 'test_output.xml'!"
+ }
+
+ set fp [open "test_output.xml" r]
+ set file_data [read $fp]
+ close $fp
+
+ if {![regexp $pattern $file_data]} {
+ error "Test failed: The file content did not match!\nFile contained:\n$file_data"
+ }
+
+ file delete "test_output.xml"
+}}
+
+test skeleton_generate_json {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {.*"skeleton:main-box": \{}
+ append pattern {.*"empty-leaf": \[null\],}
+ append pattern {.*"bool-leaf": true,}
+ append pattern {.*"num32-leaf": -100,}
+ append pattern {.*"num64-leaf": "9999999999",}
+ append pattern {.*"str-leaf": "hello",}
+ append pattern {.*"ll-empty": \[\],}
+ append pattern {.*"ll-numbers": \[}
+ append pattern {.*10,}
+ append pattern {.*20}
+ append pattern {.*],}
+ append pattern {.*"a-leaf": null,}
+ append pattern {.*"c2-leaf": "default-choice-val",}
+ append pattern {.*"server-list": \[}
+ append pattern {.*\{}
+ append pattern {.*"id": null,}
+ append pattern {.*"config": \{}
+ append pattern {.*"ip": null}
+ append pattern {.*\}}
+ append pattern {.*\}}
+ append pattern {.*\],}
+ append pattern {.*"custom-data": \{\},}
+ append pattern {.*"custom-xml": \{\},}
+ append pattern {.*"skeleton-augment:aug-leaf": "augmented-value",}
+ append pattern {.*"skeleton-augment:aug-ll": \[}
+ append pattern {.*1,}
+ append pattern {.*2}
+ append pattern {.*\]}
+ append pattern {.*\}}
+ append pattern ".*"
+
+ ly_cmd "load skeleton"
+ ly_cmd "load skeleton-augment"
+
+ ly_cmd "sample -f json skeleton" $pattern
+}}
diff --git a/tests/yanglint/interactive/sid.test b/tests/yanglint/interactive/sid.test
new file mode 100644
index 0000000000..624930db4b
--- /dev/null
+++ b/tests/yanglint/interactive/sid.test
@@ -0,0 +1,185 @@
+source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}]
+
+set mdir $::env(YANG_MODULES_DIR)
+set ddir $::env(TESTS_DIR)/data
+
+test sid_generate {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"sid-file-status": "unpublished",}
+ append pattern {.*"description": "Generated by libyang }
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"identifier": "test-sid",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1000"}
+ append pattern {.*"identifier": "/test-sid:test-container",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1001"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf1",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1002"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1003"}
+
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v1.yang"
+ ly_cmd "sid generate 1000:20 test-sid" $pattern
+}}
+
+test sid_generate_published {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {(?=.*"module-name": "test-sid",)}
+ append pattern {(?=.*"module-revision": "2026-08-11",)}
+ append pattern {(?=.*"entry-point": "1000",)}
+ append pattern {(?=.*"size": "20")}
+ append pattern {(?=.*"identifier": "test-sid",)}
+ append pattern {(?=.*"sid": "1000")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container",)}
+ append pattern {(?=.*"sid": "1001")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf1",)}
+ append pattern {(?=.*"sid": "1002")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf2",)}
+ append pattern {(?=.*"sid": "1003")}
+ append pattern {(?!.*sid-file-status)}
+ append pattern {(?!.*"status")}
+
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v1.yang"
+ ly_cmd "sid generate 1000:20 published test-sid" $pattern
+}}
+
+test sid_update {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"sid-file-version": 1,}
+ append pattern {.*"sid-file-status": "unpublished",}
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"identifier": "test-sid",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1000"}
+ append pattern {.*"identifier": "/test-sid:test-container",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1001"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf1",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1002"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"status": "obsolete",}
+ append pattern {.*"sid": "1003"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf3",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1004"}
+
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v2.yang"
+ ly_cmd "sid update $ddir/test.sid test-sid" $pattern
+}}
+
+test sid_update_published {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {(?=.*"module-name": "test-sid",)}
+ append pattern {(?=.*"module-revision": "2026-08-11",)}
+ append pattern {(?=.*"sid-file-version": 1,)}
+ append pattern {(?=.*"entry-point": "1000",)}
+ append pattern {(?=.*"size": "20")}
+ append pattern {(?=.*"identifier": "test-sid",)}
+ append pattern {(?=.*"sid": "1000")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container",)}
+ append pattern {(?=.*"sid": "1001")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf1",)}
+ append pattern {(?=.*"sid": "1002")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf2",)}
+ append pattern {(?=.*"status": "obsolete",)}
+ append pattern {(?=.*"sid": "1003")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf3",)}
+ append pattern {(?=.*"sid": "1004")}
+ append pattern {(?!.*sid-file-status)}
+ append pattern {(?!.*"unstable")}
+
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v2.yang"
+ ly_cmd "sid update $ddir/test.sid published test-sid" $pattern
+}}
+
+test sid_range_add {} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "^(?!.*sid-file-version)"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"description": "Generated by libyang }
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"entry-point": "2000",}
+ append pattern {.*"size": "10"}
+ append pattern {.*"identifier": "test-sid",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1000"}
+ append pattern {.*"identifier": "/test-sid:test-container",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1001"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf1",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1002"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1003"}
+
+ ly_cmd "sid range-add 2000:10 $ddir/test.sid" $pattern
+}}
+
+test sid_generate_output_file {Test generating .sid file into a file} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ set pattern "(?s)^"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"sid-file-status": "unpublished",}
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"identifier": "test-sid",}
+ append pattern {.*"sid": "1000"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"sid": "1003"}
+
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v1.yang"
+ ly_cmd "sid -o test_output.sid generate 1000:20 test-sid"
+
+ if {![file exists "test_output.sid"]} {
+ error "Test failed: yanglint did not create 'test_output.sid'!"
+ }
+
+ set fp [open "test_output.sid" r]
+ set file_data [read $fp]
+ close $fp
+
+ if {![regexp $pattern $file_data]} {
+ error "Test failed: The file content did not match!\nFile contained:\n$file_data"
+ }
+
+ file delete "test_output.sid"
+}}
+
+test sid_generate_multiple_modules {reject multiple module names for generate} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v1.yang"
+ ly_cmd_err "sid generate 1000:20 test-sid test-sid" "Only a single module name argument is allowed"
+}}
+
+test sid_update_multiple_modules {reject multiple module names for update} {
+-setup $ly_setup -cleanup $ly_cleanup -body {
+ ly_cmd "verb error"
+ ly_cmd "add $mdir/test-sid-v2.yang"
+ ly_cmd_err "sid update $ddir/test.sid test-sid test-sid" "Only a single module name argument is allowed"
+}}
+
+cleanupTests
diff --git a/tests/yanglint/modules/bad-ietf-prefix-namespace.yang b/tests/yanglint/modules/bad-ietf-prefix-namespace.yang
new file mode 100644
index 0000000000..aa3ed8d01e
--- /dev/null
+++ b/tests/yanglint/modules/bad-ietf-prefix-namespace.yang
@@ -0,0 +1,26 @@
+module bad-ietf-prefix-namespace {
+ yang-version 1.1;
+ namespace "urn:wrong:namespace";
+ prefix bpn;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ // Triggers 4.8: Missing "reference" and "description" inside the revision block
+ }
+}
diff --git a/tests/yanglint/modules/ietf-bad-boilerplate.yang b/tests/yanglint/modules/ietf-bad-boilerplate.yang
new file mode 100644
index 0000000000..582e234267
--- /dev/null
+++ b/tests/yanglint/modules/ietf-bad-boilerplate.yang
@@ -0,0 +1,19 @@
+module ietf-bad-boilerplate {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-bad-boilerplate";
+ prefix ibb;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+
+ // 1. Missing IETF Trust Copyright (Triggers 3.1)
+ // 2. Missing "This version of this YANG module is part of RFC..." (Triggers Appendix B)
+ // 3. Uses the word "MUST", but lacks the RFC 8174 text block (Triggers BCP 14 check)
+ description
+ "This module MUST intentionally fail the text boilerplate checks.";
+
+ revision 2026-07-08 {
+ description "Initial revision.";
+ reference "RFC XXXX: Test Module";
+ }
+}
diff --git a/tests/yanglint/modules/ietf-correct.yang b/tests/yanglint/modules/ietf-correct.yang
new file mode 100644
index 0000000000..f4fb5949ae
--- /dev/null
+++ b/tests/yanglint/modules/ietf-correct.yang
@@ -0,0 +1,60 @@
+module ietf-correct {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-correct";
+ prefix isc;
+
+ organization
+ "IETF NETMOD Working Group";
+
+ contact
+ "WG Web: ";
+
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: Test Module";
+ }
+
+ container system-info {
+ description
+ "A simple top-level container to hold our data. Notice it is
+ not mandatory.";
+
+ leaf system-name {
+ type string;
+ description
+ "The configured name of the system.";
+ }
+
+ leaf status {
+ type enumeration {
+ enum active {
+ description
+ "The system is currently active and processing.";
+ }
+ enum inactive {
+ description
+ "The system is currently inactive.";
+ }
+ }
+ description
+ "The current operational status of the system. Notice there
+ is no explicit 'config true' or 'mandatory false' here.";
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-defaults-and-mandatory.yang b/tests/yanglint/modules/ietf-defaults-and-mandatory.yang
new file mode 100644
index 0000000000..00239b6ca3
--- /dev/null
+++ b/tests/yanglint/modules/ietf-defaults-and-mandatory.yang
@@ -0,0 +1,66 @@
+module ietf-defaults-and-mandatory {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-defaults-and-mandatory";
+ prefix idm;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description "Initial revision.";
+ reference "RFC XXXX: Test Module";
+ }
+
+ extension ext1 {
+ description "Ext description";
+ argument arg1 {
+ // Triggers 4.4: yin-element given with default
+ yin-element false;
+ }
+ }
+
+ // Triggers 4.10: Top-level node cannot be mandatory
+ leaf top-mand-leaf {
+ type string;
+ description "Top level mandatory";
+ mandatory true;
+ }
+
+ leaf bad-defaults-leaf {
+ type string;
+ description "Leaf with explicit defaults";
+ // Triggers 4.4: config true
+ config true;
+ // Triggers 4.4: status current
+ status current;
+ // Triggers 4.4: mandatory false
+ mandatory false;
+ }
+
+ list bad-list {
+ key "k";
+ description "List with explicit defaults";
+ ordered-by system;
+ leaf k {
+ type string;
+ description "Key";
+ }
+ // Triggers 4.4: min-elements 0
+ min-elements 0;
+ // Triggers 4.4: max-elements unbounded
+ max-elements unbounded;
+ }
+}
diff --git a/tests/yanglint/modules/ietf-empty-type.yang b/tests/yanglint/modules/ietf-empty-type.yang
new file mode 100644
index 0000000000..feba63ea09
--- /dev/null
+++ b/tests/yanglint/modules/ietf-empty-type.yang
@@ -0,0 +1,62 @@
+module ietf-empty-type {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-empty-type";
+ prefix eett;
+
+ organization
+ "IETF NETMOD (Network Modeling) Working Group";
+
+ contact
+ "WG Web:
+ WG List:
+
+ Author: Test Author
+ ";
+
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-10 {
+ description
+ "Initial revision. Testing empty types in keys and leaf-lists.";
+ reference
+ "RFC XXXX: Guidelines for Authors and Reviewers of YANG Data Models";
+ }
+
+ container top-container {
+ description
+ "A top level container to hold our test lists.";
+
+ /* TEST 1: Trigger the 'empty' type in list key warning */
+ list list-with-empty-key {
+ key "id";
+ description
+ "A list to test the empty key warning.";
+
+ /* TEST 2: Trigger the 'empty' type in leaf */
+ leaf id {
+ type empty;
+ description
+ "Key leaf of type empty.";
+ }
+ }
+
+ /* TEST 3: Trigger the 'empty' type in leaf-list warning */
+ leaf-list leaf-list-with-empty-type {
+ type empty;
+ description
+ "A leaf-list to test the empty type warning.";
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars.yang b/tests/yanglint/modules/ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars.yang
new file mode 100644
index 0000000000..9a4c5040d4
--- /dev/null
+++ b/tests/yanglint/modules/ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars.yang
@@ -0,0 +1,90 @@
+module ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars";
+ prefix isc;
+
+ organization
+ "IETF NETMOD Working Group";
+
+ contact
+ "WG Web: ";
+
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: Test Module";
+ }
+
+ extension this-extension-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing extension identifier length.";
+ }
+
+ feature this-feature-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing feature identifier length.";
+ }
+
+ identity this-identity-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing identity identifier length.";
+ }
+
+ typedef this-typedef-identifier-is-intentionally-designed-to-exceed-64-chars {
+ type string;
+ description
+ "Testing typedef identifier length.";
+ }
+
+ grouping this-grouping-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing grouping identifier length.";
+
+ leaf dummy-leaf {
+ type string;
+ description "Needed a child to make grouping valid.";
+ }
+ }
+
+ container this-container-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing data node identifier length.";
+
+ leaf enum-tester {
+ type enumeration {
+ enum this-enum-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing enum identifier length.";
+ }
+ }
+ description
+ "Leaf to hold the long enum.";
+ }
+
+ leaf bits-tester {
+ type bits {
+ bit this-bit-identifier-is-intentionally-designed-to-exceed-64-chars {
+ description
+ "Testing bit identifier length.";
+ }
+ }
+ description
+ "Leaf to hold the long bit.";
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-imported-module.yang b/tests/yanglint/modules/ietf-imported-module.yang
new file mode 100644
index 0000000000..e46327585b
--- /dev/null
+++ b/tests/yanglint/modules/ietf-imported-module.yang
@@ -0,0 +1,26 @@
+module ietf-imported-module {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-imported-module";
+ prefix iim;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 9907; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-10 {
+ description "Initial revision.";
+ reference "RFC 9907";
+ }
+}
diff --git a/tests/yanglint/modules/ietf-list-key.yang b/tests/yanglint/modules/ietf-list-key.yang
new file mode 100644
index 0000000000..1341e89ef7
--- /dev/null
+++ b/tests/yanglint/modules/ietf-list-key.yang
@@ -0,0 +1,100 @@
+module ietf-list-key {
+ yang-version 1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-list-key";
+ prefix elkt;
+
+ organization
+ "IETF NETMOD (Network Modeling) Working Group";
+
+ contact
+ "WG Web:
+ WG List:
+
+ Author: Test Author
+ ";
+
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-10 {
+ description
+ "Initial revision. Testing list key constraints and state data must statements.";
+ reference
+ "RFC XXXX: Guidelines for Authors and Reviewers of YANG Data Models";
+ }
+
+ feature feature-a {
+ description "A test feature.";
+ }
+
+ feature feature-b {
+ description "Another test feature.";
+ }
+
+ container top-container {
+ description "A top level container to hold our test lists.";
+
+ leaf condition-tester {
+ type boolean;
+ description "A simple leaf to evaluate 'when' statements against.";
+ }
+
+ /* TEST 1: Trigger the "when" statement warning */
+ list list-with-when-on-key {
+ key "id";
+ description "A list to test the 'when' statement warning.";
+
+ leaf id {
+ type string;
+ when "../../condition-tester = 'true'";
+ description "Key leaf with an invalid when statement.";
+ }
+ }
+
+ /* TEST 2: Trigger the if-feature count mismatch error */
+ list list-missing-if-feature {
+ if-feature "feature-a";
+ key "id";
+ description "List with a feature, but the key is missing it.";
+
+ leaf id {
+ type string;
+ description "Key leaf missing the parent's if-feature.";
+ }
+ }
+
+ /* TEST 3: Trigger the if-feature string mismatch error */
+ list list-mismatched-if-feature {
+ if-feature "feature-a";
+ key "id";
+ description "List with feature-a, but the key has feature-b.";
+
+ leaf id {
+ if-feature "feature-b";
+ type string;
+ description "Key leaf with the wrong if-feature string.";
+ }
+ }
+
+ /* TEST 4: Trigger the state data constraint warning */
+ leaf state-data-with-must {
+ type string;
+ config false;
+ must "string-length(.) > 0";
+ description
+ "This leaf tests the RFC 9907 Section 4.5 recommendation to avoid
+ defining 'must' constraints on state data.";
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-miss-desc-data-nodes.yang b/tests/yanglint/modules/ietf-miss-desc-data-nodes.yang
new file mode 100644
index 0000000000..d931190450
--- /dev/null
+++ b/tests/yanglint/modules/ietf-miss-desc-data-nodes.yang
@@ -0,0 +1,58 @@
+module ietf-miss-desc-data-nodes {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-miss-desc-data-nodes";
+ prefix desc-data;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description "Initial revision.";
+ reference "RFC XXXX: Test Module";
+ }
+
+ container base-cont {
+ }
+
+ leaf top-leaf {
+ type string;
+ }
+
+ list top-list {
+ key "k";
+ leaf k {
+ type string;
+ description "Key leaf description to prevent secondary errors.";
+ }
+ }
+
+ leaf-list top-ll {
+ type string;
+ }
+
+ anyxml top-ax;
+
+ anydata top-ad;
+
+ choice top-choice {
+ case c1 {
+ leaf c-leaf {
+ type string;
+ description "Case leaf description to prevent secondary errors.";
+ }
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-miss-desc-enums-bits.yang b/tests/yanglint/modules/ietf-miss-desc-enums-bits.yang
new file mode 100644
index 0000000000..a82295a003
--- /dev/null
+++ b/tests/yanglint/modules/ietf-miss-desc-enums-bits.yang
@@ -0,0 +1,40 @@
+module ietf-miss-desc-enums-bits {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-miss-desc-enums-bits";
+ prefix desc-enum-bits;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description "Initial revision.";
+ reference "RFC XXXX: Test Module";
+ }
+
+ leaf enum-leaf {
+ type enumeration {
+ enum a;
+ }
+ description "Leaf description provided to isolate the enum warning.";
+ }
+
+ leaf bits-leaf {
+ type bits {
+ bit b;
+ }
+ description "Leaf description provided to isolate the bit warning.";
+ }
+}
diff --git a/tests/yanglint/modules/ietf-miss-desc-operations.yang b/tests/yanglint/modules/ietf-miss-desc-operations.yang
new file mode 100644
index 0000000000..f4867f91fa
--- /dev/null
+++ b/tests/yanglint/modules/ietf-miss-desc-operations.yang
@@ -0,0 +1,63 @@
+module ietf-miss-desc-operations {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-miss-desc-operations";
+ prefix desc-ops;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description "Initial revision.";
+ reference "RFC XXXX: Test Module";
+ }
+
+ rpc my-rpc {
+ input {
+ typedef in-type {
+ type string;
+ }
+ leaf rpc-in {
+ type string;
+ description "Valid description to isolate the typedef/rpc errors.";
+ }
+ }
+ }
+
+ notification my-notif {
+ leaf n-leaf {
+ type string;
+ description "Valid description to isolate the notification error.";
+ }
+ }
+
+ list action-list {
+ key "k2";
+ description "Valid list description.";
+
+ leaf k2 {
+ type string;
+ description "Valid key description.";
+ }
+
+ action my-act {
+ input {
+ leaf act-in {
+ type string;
+ }
+ }
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-miss-desc-top-level.yang b/tests/yanglint/modules/ietf-miss-desc-top-level.yang
new file mode 100644
index 0000000000..24c3094c3b
--- /dev/null
+++ b/tests/yanglint/modules/ietf-miss-desc-top-level.yang
@@ -0,0 +1,55 @@
+module ietf-miss-desc-top-level {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-miss-desc-top-level";
+ prefix desc-top;
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description "Initial revision.";
+ reference "RFC XXXX: Test Module";
+ }
+
+ extension ext1;
+
+ feature feat1;
+
+ identity id1;
+
+ typedef top-type {
+ type string;
+ }
+
+ grouping top-grp {
+ leaf x {
+ type string;
+ description "Silencing internal grouping errors.";
+ }
+ }
+
+ container cont {
+ description "Dummy container for augment target.";
+ }
+
+ augment "/desc-top:cont" {
+ // Top-level augment missing description
+ leaf a-leaf {
+ type string;
+ description "Leaf desc";
+ }
+ }
+}
diff --git a/tests/yanglint/modules/ietf-miss-meta.yang b/tests/yanglint/modules/ietf-miss-meta.yang
new file mode 100644
index 0000000000..b5a71b6b06
--- /dev/null
+++ b/tests/yanglint/modules/ietf-miss-meta.yang
@@ -0,0 +1,10 @@
+module ietf-miss-meta {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-miss-meta";
+ prefix imm;
+
+ // Triggers 4.8: missing "organization"
+ // Triggers 4.8: missing "contact"
+ // Triggers 4.8: missing "revision"
+ // Triggers 4.8: missing "description"
+}
diff --git a/tests/yanglint/modules/ietf-newer-sub.yang b/tests/yanglint/modules/ietf-newer-sub.yang
new file mode 100644
index 0000000000..928b4c9778
--- /dev/null
+++ b/tests/yanglint/modules/ietf-newer-sub.yang
@@ -0,0 +1,27 @@
+submodule ietf-newer-sub {
+ yang-version 1.1;
+ belongs-to ietf-older-main {
+ prefix om;
+ }
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG submodule is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-08 {
+ description "Newer revision.";
+ reference "RFC XXXX";
+ }
+}
diff --git a/tests/yanglint/modules/ietf-older-main.yang b/tests/yanglint/modules/ietf-older-main.yang
new file mode 100644
index 0000000000..0bd013269f
--- /dev/null
+++ b/tests/yanglint/modules/ietf-older-main.yang
@@ -0,0 +1,32 @@
+module ietf-older-main {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-older-main";
+ prefix om;
+
+ include ietf-newer-sub;
+ import ietf-imported-module {
+ prefix iim;
+ }
+
+ organization "IETF NETMOD Working Group";
+ contact "WG Web: ";
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // Triggers 4.7: Revision date is older than the submodule's date
+ revision 2020-01-01 {
+ description "Initial revision.";
+ reference "RFC XXXX";
+ }
+}
diff --git a/tests/yanglint/modules/ietf-xpath.yang b/tests/yanglint/modules/ietf-xpath.yang
new file mode 100644
index 0000000000..213b1cc131
--- /dev/null
+++ b/tests/yanglint/modules/ietf-xpath.yang
@@ -0,0 +1,76 @@
+module ietf-xpath {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-xpath";
+ prefix ixt;
+
+ organization "IETF NETMOD Working Group";
+
+ contact
+ "WG Web:
+ WG List:
+
+ Author: Test Author
+ ";
+
+ description
+ "Copyright (c) 2026 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Revised BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2026-07-10 {
+ description
+ "Initial revision. Testing banned XPath functions and axes.";
+ reference
+ "RFC XXXX: Guidelines for Authors and Reviewers of YANG Data Models";
+ }
+
+ container top-container {
+ description "A top level container to hold our test data.";
+
+ /* TEST 1: Banned function 'local-name()' in a 'when' statement */
+ container function-test-1 {
+ when "local-name() = 'function-test-1'";
+ description "Testing banned local-name() function.";
+ }
+
+ /* TEST 2: Banned function 'position()' in a 'must' statement */
+ list function-test-2 {
+ key "id";
+ must "position() < 10";
+ description "Testing banned position() function.";
+
+ leaf id {
+ type string;
+ description "Key leaf.";
+ }
+ }
+
+ /* TEST 3: Banned axis 'preceding-sibling::' in a 'when' statement */
+ leaf axis-test-1 {
+ type string;
+ when "preceding-sibling::function-test-2";
+ description "Testing banned preceding-sibling axis.";
+ }
+
+ /* TEST 4: Banned axis 'following::' in a 'must' statement */
+ leaf-list axis-test-2 {
+ type string;
+ must "following::ixt:axis-test-3 = 'test'";
+ description "Testing banned following axis.";
+ }
+
+ leaf axis-test-3 {
+ type string;
+ description "Dummy node so the 'following' axis actually finds something.";
+ }
+ }
+}
diff --git a/tests/yanglint/modules/skeleton-augment.yang b/tests/yanglint/modules/skeleton-augment.yang
new file mode 100644
index 0000000000..0d1f792efa
--- /dev/null
+++ b/tests/yanglint/modules/skeleton-augment.yang
@@ -0,0 +1,24 @@
+module skeleton-augment {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:skeleton-augment";
+ prefix sa;
+
+ import skeleton {
+ prefix sc;
+ }
+
+ // Injects these nodes into the parent from a different module
+ augment "/sc:main-box" {
+
+ leaf aug-leaf {
+ type string;
+ default "augmented-value";
+ }
+
+ leaf-list aug-ll {
+ type uint16;
+ default 1;
+ default 2;
+ }
+ }
+}
diff --git a/tests/yanglint/modules/skeleton.yang b/tests/yanglint/modules/skeleton.yang
new file mode 100644
index 0000000000..4b7b9002a2
--- /dev/null
+++ b/tests/yanglint/modules/skeleton.yang
@@ -0,0 +1,83 @@
+module skeleton {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:skeleton-complex";
+ prefix sc;
+
+ rpc do-nothing {
+ input { leaf in { type string; } }
+ }
+ notification alert {
+ leaf msg { type string; }
+ }
+
+ container main-box {
+
+ leaf empty-leaf {
+ type empty;
+ }
+
+ leaf bool-leaf {
+ type boolean;
+ default true;
+ }
+ leaf num32-leaf {
+ type int32;
+ default -100;
+ }
+ leaf num64-leaf {
+ type uint64;
+ default 9999999999;
+ }
+ leaf str-leaf {
+ type string;
+ default "hello";
+ }
+
+ leaf-list ll-empty {
+ type string;
+ }
+ leaf-list ll-numbers {
+ type uint8;
+ default 10;
+ default 20;
+ }
+
+ choice no-def-choice {
+ case a {
+ leaf a-leaf { type string; }
+ }
+ case b {
+ leaf b-leaf { type string; }
+ }
+ }
+
+ choice def-choice {
+ default case-2;
+ case case-1 {
+ leaf c1-leaf { type string; }
+ }
+ case case-2 {
+ leaf c2-leaf {
+ type string;
+ default "default-choice-val";
+ }
+ }
+ }
+
+ list server-list {
+ key "id";
+ leaf id {
+ type string;
+ }
+ action reset {
+ input { leaf delay { type uint32; } }
+ }
+ container config {
+ leaf ip { type string; }
+ }
+ }
+
+ anydata custom-data;
+ anyxml custom-xml;
+ }
+}
diff --git a/tests/yanglint/modules/test-sid-v1.yang b/tests/yanglint/modules/test-sid-v1.yang
new file mode 100644
index 0000000000..bf58b0e65a
--- /dev/null
+++ b/tests/yanglint/modules/test-sid-v1.yang
@@ -0,0 +1,18 @@
+module test-sid {
+ namespace "test:module:test-sid";
+ prefix test-sid;
+
+ description
+ "Test module for testing sid generation, update and range-add.";
+
+ revision 2026-08-11;
+
+ container test-container {
+ leaf test-leaf1 {
+ type string;
+ }
+ leaf test-leaf2 {
+ type string;
+ }
+ }
+}
diff --git a/tests/yanglint/modules/test-sid-v2.yang b/tests/yanglint/modules/test-sid-v2.yang
new file mode 100644
index 0000000000..474bf0378f
--- /dev/null
+++ b/tests/yanglint/modules/test-sid-v2.yang
@@ -0,0 +1,18 @@
+module test-sid {
+ namespace "test:module:test-sid";
+ prefix test-sid;
+
+ description
+ "Test module for testing sid generation, update and range-add.";
+
+ revision 2026-08-11;
+
+ container test-container {
+ leaf test-leaf1 {
+ type string;
+ }
+ leaf test-leaf3 {
+ type string;
+ }
+ }
+}
diff --git a/tests/yanglint/non-interactive/ietf.test b/tests/yanglint/non-interactive/ietf.test
new file mode 100644
index 0000000000..9eac8cf5db
--- /dev/null
+++ b/tests/yanglint/non-interactive/ietf.test
@@ -0,0 +1,156 @@
+source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}]
+
+set mdir $::env(YANG_MODULES_DIR)
+
+test ietf_boilerplate_bad_text {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*warning: RFC 9907: 3.1: The IETF Trust Copyright statement seems to be missing or is not correct)"
+ append pattern "(?=.*warning: RFC 9907: Appendix B: The text about which RFC this module is part of seems to be missing or is not correct)"
+ append pattern "(?=.*warning: the module seems to use RFC 2119 keywords, but the required text from RFC 8174 is not found or is not correct)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-bad-boilerplate.yang" $pattern
+} {}
+
+test ietf_long_indentifier {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier this-container-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier this-enum-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier this-feature-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier this-identity-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier this-typedef-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern "(?=.*error: RFC 9907: 4.3: identifier this-grouping-identifier-is-intentionally-designed-to-exceed-64-chars exceeds 64 characters)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-example-this-identifier-is-intentionally-designed-to-exceed-64-chars.yang" $pattern
+} {}
+
+test ietf_defaults_and_mandatory {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.10: top-level node \"top-mand-leaf\" must not be mandatory)"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"config\" is given with its default value \"true\")"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"status\" is given with its default value \"current\")"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"mandatory\" is given with its default value \"false\")"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"min-elements\" is given with its default value \"0\")"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"max-elements\" is given with its default value \"unbounded\")"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"yin-element\" is given with its default value \"false\")"
+ append pattern "(?=.*warning: RFC 9907: 4.4: statement \"ordered-by\" is given with its default value \"system\")"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-defaults-and-mandatory.yang" $pattern
+} {}
+
+test ietf_list_key {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*warning: RFC 9907: 4.5: key leaf \"id\" should not have a \"when\" statement)"
+ append pattern "(?=.*error: RFC 9907: 4.5: key leaf \"id\" must have the exact same \"if-feature\" statements as its parent list \"list-missing-if-feature\")"
+ append pattern "(?=.*error: RFC 9907: 4.5: key leaf \"id\" must have the exact same \"if-feature\" statements as its parent list \"list-mismatched-if-feature\")"
+ append pattern "(?=.*warning: RFC 9907: 4.5: constraints \\('must' statements\\) on state data should be avoided \\(leaf \"state-data-with-must\"\\))"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-list-key.yang" $pattern
+} {}
+
+test ietf_xpath {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*warning: RFC 9907: 4.6.2: XPath function in \"when\" statement on \"function-test-1\" should not be used)"
+ append pattern "(?=.*warning: RFC 9907: 4.6.2: XPath function in \"must\" statement on \"function-test-2\" should not be used)"
+ append pattern "(?=.*warning: RFC 9907: 4.6.3: XPath axis in \"when\" statement on \"axis-test-1\" should not be used)"
+ append pattern "(?=.*warning: RFC 9907: 4.6.3: XPath axis in \"must\" statement on \"axis-test-2\" should not be used)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-xpath.yang" $pattern
+} {}
+
+test ietf_boilerplate_submodule_rev {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.7: the module's revision 2020-01-01 is older than submodule ietf-newer-sub's revision 2026-07-08)"
+ append pattern "(?=.*warning: RFC 9907: 4.7: statement \"import\" for stable module \"ietf-imported-module\" should have a \"reference\" substatement)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-older-main.yang" $pattern
+} {}
+
+test ietf_boilerplate_missing_meta {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.8: statement \"module\" must have a \"contact\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.8: statement \"module\" must have a \"organization\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.8: statement \"module\" must have a \"revision\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.8: statement \"module\" must have a \"description\" substatement)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-miss-meta.yang" $pattern
+} {}
+
+test ietf_boilerplate_naming_ns {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*warning: RFC 9907: 4.1: the module name should start with one of the strings \"ietf-\" or \"iana-\")"
+ append pattern "(?=.*warning: RFC 9907: 4.9: namespace value should be \"urn:ietf:params:xml:ns:yang:bad-ietf-prefix-namespace\")"
+ append pattern "(?=.*error: RFC 9907: 4.8: statement \"revision\" 2026-07-08 must have a \"reference\" substatement)"
+ append pattern "(?=.*warning: RFC 9907: 4.8: statement \"revision\" 2026-07-08 should have a \"description\" substatement summarizing changes)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/bad-ietf-prefix-namespace.yang" $pattern
+} {}
+
+test ietf_description_enum_bits {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*warning: RFC 9907: 4.11.3: statement \"enum\" should have a \"description\" substatement)"
+ append pattern "(?=.*warning: RFC 9907: 4.11.3: statement \"bit\" should have a \"description\" substatement)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-miss-desc-enums-bits.yang" $pattern
+} {}
+
+test ietf_empty_type {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*warning: RFC 9907: 4.11.5: the type \"empty\" should not be used for a key leaf \"id\")"
+ append pattern "(?=.*warning: RFC 9907: 4.11.5: the type \"empty\" should not be used for a leaf-list \\(\"leaf-list-with-empty-type\"\\))"
+ append pattern "(?=.*warning: RFC 9907: 4.11.5: in \"id\", the \"boolean\" data type should be used instead of the \"empty\" data type)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-empty-type.yang" $pattern
+} {}
+
+test ietf_description_top {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"extension\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"grouping\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"feature\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"identity\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.13,4.14: statement \"typedef\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"augment\" must have a \"description\" substatement)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-miss-desc-top-level.yang" $pattern
+} {}
+
+test ietf_description_data_nodes {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"container\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"leaf\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"list\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"leaf-list\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"anyxml\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"choice\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"anydata\" must have a \"description\" substatement)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-miss-desc-data-nodes.yang" $pattern
+} {}
+
+test ietf_description_operations {} {
+ set pattern "(?s)^"
+ append pattern "(?=.*error: RFC 9907: 4.13,4.14: statement \"typedef\" inside input of \"my-rpc\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"leaf\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14: statement \"RPC\" must have a \"description\" substatement)"
+ append pattern "(?=.*error: RFC 9907: 4.14,4.16: statement \"notification\" must have a \"description\" substatement)"
+ append pattern ".*"
+
+ ly_cmd_err "--ietf $mdir/ietf-miss-desc-operations.yang" $pattern
+} {}
+
+test ietf_correct {} {
+ ly_cmd "--ietf $mdir/ietf-correct.yang"
+} {}
diff --git a/tests/yanglint/non-interactive/sample-skeleton.test b/tests/yanglint/non-interactive/sample-skeleton.test
new file mode 100644
index 0000000000..a7286b3730
--- /dev/null
+++ b/tests/yanglint/non-interactive/sample-skeleton.test
@@ -0,0 +1,69 @@
+source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}]
+
+set mdir $::env(YANG_MODULES_DIR)
+
+test skeleton_generate_xml {} {
+ set pattern "(?s)^"
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*true}
+ append pattern {.*-100}
+ append pattern {.*9999999999}
+ append pattern {.*hello}
+ append pattern {.*}
+ append pattern {.*10}
+ append pattern {.*20}
+ append pattern {.*}
+ append pattern {.*default-choice-val}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*}
+ append pattern {.*augmented-value}
+ append pattern {.*1}
+ append pattern {.*2}
+ append pattern {.*}
+ append pattern ".*"
+
+ ly_cmd "-S xml $mdir/skeleton.yang $mdir/skeleton-augment.yang" $pattern
+} {}
+
+test skeleton_generate_json {} {
+ set pattern "(?s)^"
+ append pattern {.*"skeleton:main-box": \{}
+ append pattern {.*"empty-leaf": \[null\],}
+ append pattern {.*"bool-leaf": true,}
+ append pattern {.*"num32-leaf": -100,}
+ append pattern {.*"num64-leaf": "9999999999",}
+ append pattern {.*"str-leaf": "hello",}
+ append pattern {.*"ll-empty": \[\],}
+ append pattern {.*"ll-numbers": \[}
+ append pattern {.*10,}
+ append pattern {.*20}
+ append pattern {.*],}
+ append pattern {.*"a-leaf": null,}
+ append pattern {.*"c2-leaf": "default-choice-val",}
+ append pattern {.*"server-list": \[}
+ append pattern {.*\{}
+ append pattern {.*"id": null,}
+ append pattern {.*"config": \{}
+ append pattern {.*"ip": null}
+ append pattern {.*\}}
+ append pattern {.*\}}
+ append pattern {.*\],}
+ append pattern {.*"custom-data": \{\},}
+ append pattern {.*"custom-xml": \{\},}
+ append pattern {.*"skeleton-augment:aug-leaf": "augmented-value",}
+ append pattern {.*"skeleton-augment:aug-ll": \[}
+ append pattern {.*1,}
+ append pattern {.*2}
+ append pattern {.*\]}
+ append pattern {.*\}}
+ append pattern ".*"
+
+ ly_cmd "-S json $mdir/skeleton.yang $mdir/skeleton-augment.yang" $pattern
+} {}
diff --git a/tests/yanglint/non-interactive/sid.test b/tests/yanglint/non-interactive/sid.test
new file mode 100644
index 0000000000..dba0de0956
--- /dev/null
+++ b/tests/yanglint/non-interactive/sid.test
@@ -0,0 +1,134 @@
+source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}]
+
+set mdir $::env(YANG_MODULES_DIR)
+set ddir $::env(TESTS_DIR)/data
+
+test sid_generate {} {
+ set pattern "(?s)^"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"sid-file-status": "unpublished",}
+ append pattern {.*"description": "Generated by libyang }
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"namespace": "module",}
+ append pattern {.*"identifier": "test-sid",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1000"}
+ append pattern {.*"namespace": "data",}
+ append pattern {.*"identifier": "/test-sid:test-container",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1001"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf1",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1002"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1003"}
+ append pattern ".*"
+
+ ly_cmd "-Q -g 1000:20 $mdir/test-sid-v1.yang" $pattern
+} {}
+
+test sid_generate_published {} {
+ set pattern "(?s)^"
+ append pattern {(?=.*"module-name": "test-sid")}
+ append pattern {(?=.*"module-revision": "2026-08-11")}
+ append pattern {(?=.*"entry-point": "1000")}
+ append pattern {(?=.*"size": "20")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf2")}
+ append pattern {(?=.*"sid": "1003")}
+ append pattern {(?!.*sid-file-status)}
+ append pattern {(?!.*"status")}
+ append pattern ".*"
+
+ ly_cmd "-Q -g 1000:20 -U $mdir/test-sid-v1.yang" $pattern
+} {}
+
+test sid_update {} {
+ set pattern "(?s)^"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"sid-file-version": 1,}
+ append pattern {.*"sid-file-status": "unpublished",}
+ append pattern {.*"description": "Generated by libyang }
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"namespace": "module",}
+ append pattern {.*"identifier": "test-sid",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1000"}
+ append pattern {.*"identifier": "/test-sid:test-container",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1001"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf1",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1002"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"status": "obsolete",}
+ append pattern {.*"sid": "1003"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf3",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1004"}
+ append pattern ".*"
+
+ ly_cmd "-Q -u $ddir/test.sid $mdir/test-sid-v2.yang" $pattern
+} {}
+
+test sid_update_published {} {
+ set pattern "(?s)^"
+ append pattern {(?=.*"module-name": "test-sid")}
+ append pattern {(?=.*"sid-file-version": 1,)}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf2")}
+ append pattern {(?=.*"status": "obsolete")}
+ append pattern {(?=.*"sid": "1003")}
+ append pattern {(?=.*"identifier": "/test-sid:test-container/test-leaf3")}
+ append pattern {(?=.*"sid": "1004")}
+ append pattern {(?!.*sid-file-status)}
+ append pattern {(?!.*"unstable")}
+ append pattern ".*"
+
+ ly_cmd "-Q -u $ddir/test.sid -U $mdir/test-sid-v2.yang" $pattern
+} {}
+
+test sid_update_range_add {} {
+ set pattern "(?s)^"
+ append pattern {.*"module-name": "test-sid",}
+ append pattern {.*"module-revision": "2026-08-11",}
+ append pattern {.*"sid-file-version": 1,}
+ append pattern {.*"sid-file-status": "unpublished",}
+ append pattern {.*"description": "Generated by libyang }
+ append pattern {.*"entry-point": "1000",}
+ append pattern {.*"size": "20"}
+ append pattern {.*"entry-point": "2000",}
+ append pattern {.*"size": "10"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf2",}
+ append pattern {.*"status": "obsolete",}
+ append pattern {.*"sid": "1003"}
+ append pattern {.*"identifier": "/test-sid:test-container/test-leaf3",}
+ append pattern {.*"status": "unstable",}
+ append pattern {.*"sid": "1004"}
+ append pattern ".*"
+
+ ly_cmd "-Q -u $ddir/test.sid -r 2000:10 $mdir/test-sid-v2.yang" $pattern
+} {}
+
+test sid_duplicate_range {} {
+ set pattern "can be specified only once"
+
+ ly_cmd_err "-g 1000:20 -r 2000:10 $mdir/test-sid-v1.yang" $pattern
+} {}
+
+test sid_range_add_without_update {} {
+ set pattern "can be used only in combination with"
+
+ ly_cmd_err "-r 2000:10 $mdir/test-sid-v1.yang" $pattern
+} {}
+
+test sid_generate_with_update {} {
+ set pattern "cannot be combined with"
+
+ ly_cmd_err "-g 1000:20 -u $ddir/test.sid $mdir/test-sid-v2.yang" $pattern
+} {}
+
+cleanupTests
diff --git a/tools/lint/CMakeLists.txt b/tools/lint/CMakeLists.txt
index 42d43093bf..55f014d1b7 100644
--- a/tools/lint/CMakeLists.txt
+++ b/tools/lint/CMakeLists.txt
@@ -14,6 +14,9 @@ set(lintsrc
cmd_help.c
cmd_verb.c
cmd_debug.c
+ cmd_sample.c
+ cmd_sid.c
+ ietf.c
yl_opt.c
yl_schema_features.c
common.c
diff --git a/tools/lint/cmd.c b/tools/lint/cmd.c
index 1f1e791f5b..2938380df3 100644
--- a/tools/lint/cmd.c
+++ b/tools/lint/cmd.c
@@ -72,6 +72,14 @@ COMMAND commands[] = {
"data", cmd_data_opt, cmd_data_dep, cmd_data_store, cmd_data_process, cmd_data_help, NULL,
"Load, validate and optionally print instance data", "d:ef:F:hmo:O:R:r:nt:x:k:"
},
+ {
+ "sample", cmd_sample_opt, cmd_sample_dep, cmd_sample_exec, NULL, cmd_sample_help, NULL,
+ "Generate a sample data skeleton for a module", "f:ho:"
+ },
+ {
+ "sid", cmd_sid_opt, cmd_sid_dep, cmd_sid_exec, NULL, cmd_sid_help, NULL,
+ "Generate, update or extend a .sid file of a loaded module (RFC 9595)", "ho:f:"
+ },
{
"list", cmd_list_opt, cmd_list_dep, cmd_list_exec, NULL, cmd_list_help, NULL,
"List all the loaded modules", "f:h"
diff --git a/tools/lint/cmd.h b/tools/lint/cmd.h
index e9ee5b4920..29425082cf 100644
--- a/tools/lint/cmd.h
+++ b/tools/lint/cmd.h
@@ -73,6 +73,8 @@ enum COMMAND_INDEX {
CMD_LOAD,
CMD_PRINT,
CMD_DATA,
+ CMD_SAMPLE,
+ CMD_SID,
CMD_LIST,
CMD_FEATURE,
CMD_SEARCHPATH,
@@ -276,6 +278,56 @@ int cmd_print_dep(struct yl_opt *yo, int posc);
int cmd_print_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
void cmd_print_help(void);
+/* cmd_sample.c */
+
+/**
+ * @copydoc cmd_add_opt
+ */
+int cmd_sample_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc);
+
+/**
+ * @copydoc cmd_add_dep
+ */
+int cmd_sample_dep(struct yl_opt *yo, int posc);
+void cmd_sample_help(void);
+
+/**
+ * @brief Print a sample skeleton of module in json or xml.
+ *
+ * @param[in,out] ctx context for libyang.
+ * @param[in] yo context for yanglint.
+ * @param[in] posv Name of the module to be printed.
+ * @return 0 on success, 1 on failure.
+ */
+int cmd_sample_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
+
+/* cmd_sid.c */
+
+/**
+ * @copydoc cmd_add_opt
+ */
+int cmd_sid_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc);
+
+/**
+ * @copydoc cmd_add_dep
+ */
+int cmd_sid_dep(struct yl_opt *yo, int posc);
+void cmd_sid_help(void);
+
+/**
+ * @brief Process the .sid file of a module (generate/update/range-add, RFC 9595) based on
+ * the set SID options: no previous file generates, a previous file updates (optionally
+ * adding a new assignment range first), both a range and a previous file in the interactive
+ * mode just extends the previous file with the new range.
+ *
+ * @param[in,out] ctx context for libyang.
+ * @param[in,out] yo context for yanglint, holds all the SID options.
+ * @param[in] posv Name of the module to process for generation/update, NULL for the
+ * standalone (interactive) range addition.
+ * @return 0 on success, 1 on failure.
+ */
+int cmd_sid_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
+
/* cmd_searchpath.c */
/**
diff --git a/tools/lint/cmd_add.c b/tools/lint/cmd_add.c
index 9f107110ab..f9b13b42a7 100644
--- a/tools/lint/cmd_add.c
+++ b/tools/lint/cmd_add.c
@@ -130,7 +130,8 @@ store_parsed_module(const char *filepath, struct lys_module *mod, struct yl_opt
{
assert(!yo->interactive);
- if (yo->schema_out_format || yo->feature_param_format) {
+ if (yo->schema_out_format || yo->feature_param_format || yo->sample_skeleton || yo->ietf_validation ||
+ yo->sid_range || yo->sid_prev_path) {
if (ly_set_add(&yo->schema_modules, (void *)mod, 1, NULL)) {
YLMSG_E("Storing parsed schema module (%s) for print failed.", filepath);
return 1;
diff --git a/tools/lint/cmd_sample.c b/tools/lint/cmd_sample.c
new file mode 100644
index 0000000000..3747193091
--- /dev/null
+++ b/tools/lint/cmd_sample.c
@@ -0,0 +1,566 @@
+/**
+ * @file cmd_sample.c
+ * @author Petr Hanzlik
+ * @brief 'sample-skeleton' command of the libyang's yanglint tool.
+ *
+ * Copyright (c) 2026 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 _GNU_SOURCE
+
+#include "cmd.h"
+
+#include
+#include
+#include
+
+#include "libyang.h"
+
+#include "common.h"
+#include "yl_opt.h"
+
+#define SPACE_COUNT 2
+
+static void print_xml_nodes(struct ly_out *out, const struct lysc_node *node, int space_count);
+static void print_json_nodes(struct ly_out *out, const struct lysc_node *node, const char *name, int space_count, int *need_comma);
+
+void
+cmd_sample_help(void)
+{
+ printf("Usage: sample [-f (xml | json)] [-o OUTFILE] [@revision]\n"
+ " Generate and print a sample data skeleton from a loaded schema module.\n\n"
+ " -f FORMAT, --format=FORMAT\n"
+ " Print the sample skeleton in the specified FORMAT.\n"
+ " Supported formats: xml, json.\n"
+ " -o OUTFILE, --output=OUTFILE\n"
+ " Write the output to OUTFILE instead of stdout.\n"
+ " -h, --help\n"
+ " Display this help message.\n");
+}
+
+int
+cmd_sample_dep(struct yl_opt *yo, int posc)
+{
+ if (yo->interactive && !posc) {
+ YLMSG_E("Missing module name to generate skeleton for.\n");
+ return 1;
+ }
+
+ if (!yo->data_out_format) {
+ YLMSG_E("Missing required format (-f xml | json).\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+cmd_sample_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
+{
+ int rc = 0, argc = 0;
+ int opt, opt_index;
+ char **argv = NULL;
+ struct option options[] = {
+ {"format", required_argument, NULL, 'f'},
+ {"output", required_argument, NULL, 'o'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ if ((rc = parse_cmdline(cmdline, &argc, &argv))) {
+ return rc;
+ }
+
+ /* reset getopt */
+ optind = 0;
+ while ((opt = getopt_long(argc, argv, "f:o:h", options, &opt_index)) != -1) {
+ switch (opt) {
+ case 'f': /* --format */
+ if (yl_opt_update_data_out_format(optarg, yo)) {
+ rc = 1;
+ goto cleanup;
+ }
+ break;
+
+ case 'o': /* --output */
+ if (yo->out) {
+ ly_out_free(yo->out, NULL, 0);
+ yo->out = NULL;
+ }
+ if (ly_out_new_filepath(optarg, &yo->out)) {
+ YLMSG_E("Unable to open output file %s.\n", optarg);
+ rc = 1;
+ goto cleanup;
+ }
+ break;
+
+ case 'h': /* --help */
+ cmd_sample_help();
+ rc = 1;
+ goto cleanup;
+
+ default:
+ YLMSG_E("Unknown option.\n");
+ rc = 1;
+ goto cleanup;
+ }
+ }
+
+ *posc = argc - optind;
+ *posv = &argv[optind];
+
+ return 0;
+
+cleanup:
+ free_cmdline(argv);
+ return rc;
+}
+
+/**
+ * @brief Print a specific number of spaces for indentation.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] count Number of spaces to print.
+ */
+static void
+print_space(struct ly_out *out, int count)
+{
+ for (int i = 0; i < count; i++) {
+ ly_print(out, " ");
+ }
+}
+
+/**
+ * @brief Handle and print the default values or closing XML tags for a schema node.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] node Compiled schema node currently being processed.
+ * @param[in] space_count Current indentation level (number of spaces).
+ */
+static void
+handle_xml_default(struct ly_out *out, const struct lysc_node *node, int space_count)
+{
+ switch (node->nodetype) {
+ case LYS_LEAF: {
+ struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
+
+ if (leaf->dflt.str) {
+ ly_print(out, ">%s%s>\n", leaf->dflt.str, node->name);
+ } else {
+ ly_print(out, "/>\n");
+ }
+ break;
+ }
+ case LYS_LEAFLIST: {
+ struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
+
+ if (llist->dflts) {
+ LY_ARRAY_COUNT_TYPE i;
+
+ LY_ARRAY_FOR(llist->dflts, i) {
+ print_space(out, space_count);
+ if (node->parent && (node->module != node->parent->module)) {
+ ly_print(out, "<%s xmlns=\"%s\">%s%s>\n", llist->name, node->module->ns, llist->dflts[i].str, llist->name);
+ } else {
+ ly_print(out, "<%s>%s%s>\n", llist->name, llist->dflts[i].str, llist->name);
+ }
+ }
+ } else {
+ print_space(out, space_count);
+ if (node->parent && (node->module != node->parent->module)) {
+ ly_print(out, "<%s xmlns=\"%s\">%s>\n", llist->name, node->module->ns, llist->name);
+ } else {
+ ly_print(out, "<%s>%s>\n", llist->name, llist->name);
+ }
+ }
+ break;
+ }
+ case LYS_CHOICE: {
+ struct lysc_node_choice *choice = (struct lysc_node_choice *)node;
+
+ if (choice->dflt) {
+ print_xml_nodes(out, lysc_node_child((const struct lysc_node *)choice->dflt), space_count);
+ } else {
+ if (lysc_node_child(node)) {
+ print_xml_nodes(out, lysc_node_child(lysc_node_child(node)), space_count);
+ }
+ }
+ break;
+ }
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ ly_print(out, "/>\n");
+ break;
+ }
+}
+
+/**
+ * @brief Traverse the compiled schema tree and print XML skeleton tags.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] node Compiled schema node to begin traversing.
+ * @param[in] space_count Current indentation level.
+ */
+static void
+print_xml_nodes(struct ly_out *out, const struct lysc_node *node, int space_count)
+{
+ const uint32_t PRINT_MASK = LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_ANYXML | LYS_ANYDATA;
+ int nodetype;
+
+ while (node) {
+ nodetype = node->nodetype;
+
+ if (nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ node = node->next;
+ continue;
+ }
+
+ if (nodetype & PRINT_MASK) {
+ print_space(out, space_count);
+
+ if (!node->parent) {
+ ly_print(out, "<%s xmlns=\"%s\"", node->name, node->module->ns);
+ } else if (node->parent && (node->module != node->parent->module)) {
+ ly_print(out, "<%s xmlns=\"%s\"", node->name, node->module->ns);
+ } else {
+ ly_print(out, "<%s", node->name);
+ }
+ }
+
+ if (lysc_node_child(node)) {
+ if (nodetype & PRINT_MASK) {
+ ly_print(out, ">\n");
+ }
+
+ if (nodetype == LYS_CHOICE) {
+ handle_xml_default(out, node, space_count);
+ node = node->next;
+ continue;
+ } else {
+ print_xml_nodes(out, lysc_node_child(node), space_count + SPACE_COUNT);
+ }
+
+ if (nodetype & PRINT_MASK) {
+ print_space(out, space_count);
+ ly_print(out, "%s>\n", node->name);
+ }
+ } else {
+ handle_xml_default(out, node, space_count);
+ }
+
+ node = node->next;
+ }
+}
+
+/**
+ * @brief Initialize and print the top-level XML skeleton structure.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] root Root compiled schema node of the module being processed.
+ */
+static void
+print_xml_skeleton(struct ly_out *out, struct lysc_node *root)
+{
+ struct lysc_node *node = root;
+ int spaces = SPACE_COUNT;
+
+ ly_print(out, "\n"
+ "\n");
+ print_xml_nodes(out, node, spaces);
+ ly_print(out, "\n");
+
+}
+
+/**
+ * @brief Determine if a YANG base type requires string quotes in JSON encoding.
+ *
+ * @param[in] basetype Libyang data type to evaluate.
+ * @return 1 if the type requires quotes (string-like), 0 if it must be printed raw (numeric/boolean).
+ */
+static int
+is_json_quote_required(LY_DATA_TYPE basetype)
+{
+ switch (basetype) {
+ case LY_TYPE_INT8:
+ case LY_TYPE_INT16:
+ case LY_TYPE_INT32:
+ case LY_TYPE_UINT8:
+ case LY_TYPE_UINT16:
+ case LY_TYPE_UINT32:
+ case LY_TYPE_BOOL:
+ return 0;
+
+ case LY_TYPE_UNKNOWN:
+ case LY_TYPE_STRING:
+ case LY_TYPE_INT64:
+ case LY_TYPE_UINT64:
+ case LY_TYPE_DEC64:
+ case LY_TYPE_BINARY:
+ case LY_TYPE_BITS:
+ case LY_TYPE_ENUM:
+ case LY_TYPE_IDENT:
+ case LY_TYPE_INST:
+ case LY_TYPE_LEAFREF:
+ case LY_TYPE_UNION:
+ case LY_TYPE_EMPTY:
+ return 1;
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Handle and print the default values or closing JSON tags for a schema node.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] node Compiled schema node currently being processed.
+ * @param[in] space_count Current indentation level (number of spaces).
+ * @param[in,out] need_comma Pointer to the comma state variable.
+ */
+static void
+handle_json_default(struct ly_out *out, const struct lysc_node *node, int space_count, int *need_comma)
+{
+ switch (node->nodetype) {
+ case LYS_LEAF: {
+ struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
+
+ if (leaf->dflt.str) {
+ if (is_json_quote_required(leaf->type->basetype)) {
+ ly_print(out, " \"%s\"", leaf->dflt.str);
+ } else {
+ ly_print(out, " %s", leaf->dflt.str);
+ }
+ } else {
+ if (leaf->type->basetype == LY_TYPE_EMPTY) {
+ ly_print(out, " [null]");
+ } else {
+ ly_print(out, " null");
+ }
+ }
+ break;
+ }
+ case LYS_LEAFLIST: {
+ struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
+
+ if (llist->dflts) {
+ LY_ARRAY_COUNT_TYPE i;
+
+ ly_print(out, " [\n");
+
+ LY_ARRAY_FOR(llist->dflts, i) {
+ if (i == 0) {
+ print_space(out, space_count + SPACE_COUNT);
+ } else {
+ ly_print(out, ",\n");
+ print_space(out, space_count + SPACE_COUNT);
+ }
+
+ if (is_json_quote_required(llist->type->basetype)) {
+ ly_print(out, "\"%s\"", llist->dflts[i].str);
+ } else {
+ ly_print(out, "%s", llist->dflts[i].str);
+ }
+ }
+ ly_print(out, "\n");
+ print_space(out, space_count);
+ ly_print(out, "]");
+ } else {
+ ly_print(out, " []");
+ }
+ break;
+ }
+ case LYS_CHOICE: {
+ struct lysc_node_choice *choice = (struct lysc_node_choice *)node;
+
+ if (choice->dflt) {
+ print_json_nodes(out, lysc_node_child((const struct lysc_node *)choice->dflt), NULL, space_count, need_comma);
+ } else {
+ if (lysc_node_child(node)) {
+ print_json_nodes(out, lysc_node_child(lysc_node_child(node)), NULL, space_count, need_comma);
+ }
+ }
+ break;
+ }
+ case LYS_CONTAINER:
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ ly_print(out, " {}");
+ break;
+ case LYS_LIST:
+ ly_print(out, " []");
+ break;
+ }
+}
+
+/**
+ * @brief Traverse the compiled schema tree and print JSON skeleton tags.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] node Compiled schema node to begin traversing.
+ * @param[in] name Name of the module, or NULL if inherited.
+ * @param[in] space_count Current indentation level; dynamically incremented and decremented during traversal.
+ * @param[in,out] need_comma Pointer to the state variable tracking JSON comma formatting. Set to 1 if a trailing comma is required before printing the * next sibling, or 0 if the node is the first element in a block.
+ */
+static void
+print_json_nodes(struct ly_out *out, const struct lysc_node *node, const char *name, int space_count, int *need_comma)
+{
+ int nodetype;
+ const uint32_t PRINT_MASK = LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_ANYXML | LYS_ANYDATA | LYS_LEAFLIST;
+
+ while (node) {
+ nodetype = node->nodetype;
+
+ if (nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ node = node->next;
+ continue;
+ }
+
+ if (nodetype & PRINT_MASK) {
+ if (*need_comma) {
+ ly_print(out, ",\n");
+ }
+
+ print_space(out, space_count);
+
+ if (name && !node->parent) {
+ ly_print(out, "\"%s:%s\":", node->module->name, node->name);
+ } else if (node->parent && (node->module != node->parent->module)) {
+ ly_print(out, "\"%s:%s\":", node->module->name, node->name);
+ } else {
+ ly_print(out, "\"%s\":", node->name);
+ }
+ }
+
+ if (lysc_node_child(node)) {
+ if (nodetype & PRINT_MASK) {
+ if (nodetype == LYS_LIST) {
+ ly_print(out, " [\n");
+ print_space(out, space_count + SPACE_COUNT);
+ ly_print(out, "{\n");
+ space_count += 2 * SPACE_COUNT;
+ } else {
+ ly_print(out, " {\n");
+ space_count += SPACE_COUNT;
+ }
+ *need_comma = 0;
+ }
+
+ if (nodetype == LYS_CHOICE) {
+ handle_json_default(out, node, space_count, need_comma);
+ node = node->next;
+ continue;
+ } else {
+ print_json_nodes(out, lysc_node_child(node), NULL, space_count, need_comma);
+ }
+
+ if (nodetype & PRINT_MASK) {
+ if (nodetype == LYS_LIST) {
+ space_count -= SPACE_COUNT;
+ ly_print(out, "\n");
+ print_space(out, space_count);
+ ly_print(out, "}\n");
+ space_count -= SPACE_COUNT;
+ print_space(out, space_count);
+ ly_print(out, "]");
+ } else {
+ space_count -= SPACE_COUNT;
+ ly_print(out, "\n");
+ print_space(out, space_count);
+ ly_print(out, "}");
+ }
+ *need_comma = 1;
+ }
+ } else {
+ handle_json_default(out, node, space_count, need_comma);
+
+ if (nodetype & PRINT_MASK) {
+ *need_comma = 1;
+ }
+ }
+
+ node = node->next;
+ }
+}
+
+/**
+ * @brief Initialize and print the top-level JSON skeleton structure.
+ *
+ * @param[in,out] out Libyang output handler to print to.
+ * @param[in] root Root compiled schema node of the module being processed.
+ * @param[in] name Name of the module, used to correctly prefix the top-level JSON objects according to RFC 7951 namespace rules.
+ */
+static void
+print_json_skeleton(struct ly_out *out, struct lysc_node *root, const char *name)
+{
+ struct lysc_node *node = root;
+ int spaces = SPACE_COUNT, need_comma = 0;
+
+ ly_print(out, "{\n");
+ print_json_nodes(out, node, name, spaces, &need_comma);
+ ly_print(out, "\n}\n");
+}
+
+int
+cmd_sample_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv)
+{
+ const struct lys_module *mod;
+ char *revision, *name;
+ uint8_t out_alloc = 0;
+
+ name = strdup(posv);
+ if (!name) {
+ YLMSG_E("Memory allocation failed.");
+ return 1;
+ }
+ revision = strchr(name, '@');
+ if (revision) {
+ revision[0] = '\0';
+ ++revision;
+ }
+
+ mod = revision ?
+ ly_ctx_get_module(*ctx, name, revision) :
+ ly_ctx_get_module_latest(*ctx, name);
+
+ if (!mod || !mod->compiled) {
+ YLMSG_E("Error: Module %s not loaded or has no compiled schema.", name);
+ free(name);
+ return 1;
+ }
+
+ if (!mod->compiled->data) {
+ free(name);
+ return 0;
+ }
+
+ if (!yo->out) {
+ if (ly_out_new_file(stdout, &yo->out)) {
+ YLMSG_E("Unable to allocate output handler.");
+ free(name);
+ return 1;
+ }
+ out_alloc = 1;
+ }
+
+ if (yo->data_out_format == LYD_XML) {
+ print_xml_skeleton(yo->out, mod->compiled->data);
+ } else {
+ print_json_skeleton(yo->out, mod->compiled->data, mod->name);
+ }
+
+ if (out_alloc) {
+ ly_out_free(yo->out, NULL, 0);
+ yo->out = NULL;
+ }
+
+ free(name);
+ return 0;
+}
diff --git a/tools/lint/cmd_sid.c b/tools/lint/cmd_sid.c
new file mode 100644
index 0000000000..762d9cb3bf
--- /dev/null
+++ b/tools/lint/cmd_sid.c
@@ -0,0 +1,431 @@
+/**
+ * @file cmd_sid.c
+ * @author Petr Hanzlik
+ * @brief Processing of .sid files in the libyang's yanglint tool.
+ *
+ * Copyright (c) 2026 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 _GNU_SOURCE
+
+#include "cmd.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "libyang.h"
+
+#include "common.h"
+#include "yl_opt.h"
+
+/* processes the positional arguments specific for a .sid file operation (defined below) */
+static int process_sid_args(const char *op, int *argc, char **argv, struct yl_opt *yo);
+
+void
+cmd_sid_help(void)
+{
+ printf("Usage: sid [-o OUTFILE] [-f FORMAT] [arguments]\n"
+ " Generate, update or extend a .sid file of a loaded schema module (RFC 9595).\n\n"
+ " Operations:\n"
+ " generate EP:SIZE [published] [@revision]\n"
+ " Generate a new .sid file for the module.\n"
+ " update [published] [@revision]\n"
+ " Update an existing .sid file for the module.\n"
+ " range-add EP:SIZE \n"
+ " Add a new assignment range to an existing .sid file.\n\n"
+ " EP (Entry Point) is the first SID of the new assignment range, SIZE the\n"
+ " number of SIDs to assign (must not be 0).\n"
+ " Without the 'published' keyword, the status is 'unpublished'.\n"
+ " -o OUTFILE, --output=OUTFILE\n"
+ " Write the output to OUTFILE instead of stdout.\n"
+ " -f FORMAT, --format=FORMAT\n"
+ " Output data format (json (default) or xml).\n"
+ " -h, --help Display this help message.\n");
+}
+
+int
+cmd_sid_dep(struct yl_opt *yo, int posc)
+{
+ if (yo->sid_range && yo->sid_prev_path) {
+ /* interactive range-add */
+ if (posc) {
+ YLMSG_E("Unexpected module name argument(s) for the SID range-add operation.\n");
+ return 1;
+ }
+ } else if (yo->interactive) {
+ if (!posc) {
+ /* generate or update needs the target module */
+ YLMSG_E("Missing the module name to process.\n");
+ return 1;
+ } else if (posc > 1) {
+ YLMSG_E("Only a single module name argument is allowed.\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+cmd_sid_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
+{
+ int rc = 0, argc = 0;
+ int opt, opt_index;
+ const char *op;
+ struct option options[] = {
+ {"output", required_argument, NULL, 'o'},
+ {"format", required_argument, NULL, 'f'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ if ((rc = parse_cmdline(cmdline, &argc, &yo->argv))) {
+ return rc;
+ }
+
+ optind = 0;
+ while ((opt = getopt_long(argc, yo->argv, commands[CMD_SID].optstring, options, &opt_index)) != -1) {
+ switch (opt) {
+ case 'o': /* --output */
+ if (yo->out) {
+ ly_out_free(yo->out, NULL, 0);
+ yo->out = NULL;
+ }
+ if (ly_out_new_filepath(optarg, &yo->out)) {
+ YLMSG_E("Unable to open output file %s.\n", optarg);
+ return 1;
+ }
+ break;
+ case 'f': /* --format */
+ if (yo->data_out_format) {
+ YLMSG_E("The output data format can be specified only once.\n");
+ return 1;
+ }
+ if (yl_opt_update_data_out_format(optarg, yo)) {
+ YLMSG_E("Invalid output data format \"%s\".\n", optarg);
+ return 1;
+ }
+ break;
+ case 'h': /* --help */
+ cmd_sid_help();
+ return 1;
+ default:
+ YLMSG_E("Unknown option.\n");
+ return 1;
+ }
+ }
+
+ /* the first positional argument must be the operation */
+ if (optind >= argc) {
+ YLMSG_E("Missing the SID operation (generate, update or range-add).\n");
+ return 1;
+ }
+ if (strcmp(yo->argv[optind], "generate") && strcmp(yo->argv[optind], "update") &&
+ strcmp(yo->argv[optind], "range-add")) {
+ YLMSG_E("Unknown SID operation \"%s\" (use generate, update or range-add).\n", yo->argv[optind]);
+ return 1;
+ }
+ op = yo->argv[optind];
+ optind++;
+
+ /* parse the SID-specific positional arguments */
+ if (process_sid_args(op, &argc, yo->argv, yo)) {
+ return 1;
+ }
+
+ *posc = argc - optind;
+ *posv = &yo->argv[optind];
+
+ return 0;
+}
+
+/**
+ * @brief Parse a positional argument in the EP:SIZE SID assignment range format.
+ *
+ * @param[in] sid_range Argument to parse.
+ * @param[out] entry_point Parsed entry point.
+ * @param[out] range_size Parsed range size.
+ * @return 0 if @p sid_range is a valid EP:SIZE range, 1 otherwise.
+ */
+static int
+parse_sid_range(const char *sid_range, uint64_t *entry_point, uint64_t *range_size)
+{
+ char *end;
+ unsigned long long ep, len;
+
+ errno = 0;
+ ep = strtoull(sid_range, &end, 10);
+ if ((end == sid_range) || errno || (*end != ':')) {
+ return 1;
+ }
+ end++;
+
+ errno = 0;
+ len = strtoull(end, &end, 10);
+ if (!end || *end || errno) {
+ return 1;
+ }
+
+ *entry_point = (uint64_t)ep;
+ *range_size = (uint64_t)len;
+ return 0;
+}
+
+/**
+ * @brief Process the positional arguments of the interactive 'sid' command (an optional
+ * EP:SIZE range, an optional 'published' keyword, and the previous .sid file for the
+ * 'update'/'range-add' operations) and store them into the SID fields of ::yl_opt.
+ *
+ * @param[in] op The sid command operation ("generate", "update", or "range-add").
+ * @param[in,out] argc Number of parsed arguments, updated to the remaining ones.
+ * @param[in,out] argv Parsed arguments, updated to the remaining ones.
+ * @param[in,out] yo yanglint options to store the SID values into.
+ * @return 0 on success, 1 on error (message already printed).
+ */
+static int
+process_sid_args(const char *op, int *argc, char **argv, struct yl_opt *yo)
+{
+ int i, j;
+ uint64_t ep, size;
+ size_t len;
+
+ for (i = optind, j = optind; i < *argc; i++) {
+ /* the EP:SIZE assignment range */
+ if (!parse_sid_range(argv[i], &ep, &size)) {
+ if (!strcmp(op, "update")) {
+ YLMSG_E("The EP:SIZE range is not a valid argument for the SID update operation.");
+ return 1;
+ }
+ if (yo->sid_range) {
+ YLMSG_E("The EP:SIZE range can be specified only once.");
+ return 1;
+ }
+ if (!size) {
+ YLMSG_E("The SID range size must not be zero.");
+ return 1;
+ }
+ yo->sid_range = strdup(argv[i]);
+ if (!yo->sid_range) {
+ YLMSG_E("Memory allocation failed.");
+ return 1;
+ }
+ continue;
+ }
+
+ /* the 'published' status keyword */
+ if (!strcmp(argv[i], "published")) {
+ if (!strcmp(op, "range-add")) {
+ YLMSG_E("The 'published' status is not a valid argument for the SID range-add operation.");
+ return 1;
+ }
+ if (yo->sid_publish) {
+ YLMSG_E("The 'published' status can be specified only once.");
+ return 1;
+ }
+ yo->sid_publish = 1;
+ continue;
+ }
+
+ /* the .sid file */
+ len = strlen(argv[i]);
+ if ((len > 4) && !strcmp(argv[i] + len - 4, ".sid")) {
+ if (!strcmp(op, "generate")) {
+ YLMSG_E("A .sid file is not a valid argument for the SID generate operation.");
+ return 1;
+ }
+ if (yo->sid_prev_path) {
+ YLMSG_E("Only a single previous .sid file can be specified.");
+ return 1;
+ }
+ yo->sid_prev_path = strdup(argv[i]);
+ if (!yo->sid_prev_path) {
+ YLMSG_E("Memory allocation failed.");
+ return 1;
+ }
+ continue;
+ }
+
+ /* keep all the other arguments for further processing */
+ argv[j] = argv[i];
+ j++;
+ }
+ argv[j] = NULL;
+ *argc = j;
+
+ /* check the mandatory arguments */
+ if (strcmp(op, "update") && !yo->sid_range) {
+ YLMSG_E("Missing the SID assignment range EP:SIZE.");
+ return 1;
+ }
+ if (strcmp(op, "generate") && !yo->sid_prev_path) {
+ YLMSG_E("Missing the previous .sid file to process.");
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Check the EP:SIZE SID assignment range option and parse it.
+ *
+ * @param[in] yo yanglint options with the range string (must be set).
+ * @param[out] ep Parsed entry point.
+ * @param[out] size Parsed range size.
+ * @return 0 on success, 1 on failure with an error message printed.
+ */
+static int
+sid_check_range(const struct yl_opt *yo, uint64_t *ep, uint64_t *size)
+{
+ if (parse_sid_range(yo->sid_range, ep, size) || !*size) {
+ YLMSG_E("Bad format of the SID range \"%s\", expected EP:SIZE with a nonzero SIZE.", yo->sid_range);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Print the resulting .sid file data tree in the requested data format (JSON by default)
+ * to the prepared output.
+ *
+ * @param[in,out] yo yanglint options with the prepared output handler.
+ * @param[in] sid_file The .sid file data tree to print.
+ * @return 0 on success, 1 on failure.
+ */
+static int
+sid_print(struct yl_opt *yo, struct lyd_node *sid_file)
+{
+ int rc = 0;
+ uint8_t out_alloc = 0;
+ LYD_FORMAT format = LYD_JSON;
+
+ if (yo->data_out_format) {
+ format = yo->data_out_format;
+ }
+
+ if (!yo->out) {
+ if (ly_out_new_file(stdout, &yo->out)) {
+ YLMSG_E("Unable to allocate output handler.");
+ return 1;
+ }
+ out_alloc = 1;
+ }
+
+ if (lyd_print_all(yo->out, sid_file, format, 0)) {
+ YLMSG_E("Printing the .sid file failed.");
+ rc = 1;
+ } else {
+ ly_print_flush(yo->out);
+ }
+
+ if (out_alloc) {
+ ly_out_free(yo->out, NULL, 0);
+ yo->out = NULL;
+ }
+
+ return rc;
+}
+
+int
+cmd_sid_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv)
+{
+ int rc = 1;
+ const struct lys_module *mod = NULL;
+ struct lyd_node *prev = NULL, *sid_file = NULL;
+ char *name = NULL, *revision;
+ uint64_t ep = 0, size = 0;
+ LYS_SID_FILE_STATUS status = yo->sid_publish ? LYS_SID_FILE_PUBLISHED : LYS_SID_FILE_UNPUBLISHED;
+
+ /* make sure the ietf-sid-file module is implemented in the context */
+ if (!ly_ctx_get_module_implemented(*ctx, "ietf-sid-file") &&
+ !ly_ctx_load_module(*ctx, "ietf-sid-file", NULL, NULL)) {
+ YLMSG_E("Unable to load the ietf-sid-file module required for SID processing.");
+ return 1;
+ }
+
+ if (yo->sid_range && sid_check_range(yo, &ep, &size)) {
+ return 1;
+ }
+
+ /* generate and update always have the target module, the standalone range-add does not */
+ if (posv) {
+ name = strdup(posv);
+ if (!name) {
+ YLMSG_E("Memory allocation failed.");
+ return 1;
+ }
+ revision = strchr(name, '@');
+ if (revision) {
+ revision[0] = '\0';
+ revision++;
+ }
+
+ mod = revision ?
+ ly_ctx_get_module(*ctx, name, revision) :
+ ly_ctx_get_module_latest(*ctx, name);
+
+ if (!mod) {
+ YLMSG_E("Module \"%s\" not loaded.", name);
+ goto cleanup;
+ }
+ if (!mod->compiled && lys_set_implemented((struct lys_module *)mod, NULL)) {
+ YLMSG_E("Implementing module \"%s\" failed.", mod->name);
+ goto cleanup;
+ }
+ }
+
+ if (yo->sid_prev_path) {
+ /* parse the previous .sid file */
+ if (lyd_parse_data_path(*ctx, yo->sid_prev_path, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &prev)) {
+ YLMSG_E("Failed to parse the previous .sid file \"%s\".", yo->sid_prev_path);
+ goto cleanup;
+ }
+ }
+
+ if (yo->sid_range && yo->sid_prev_path) {
+ /* add the new assignment range first */
+ if (lys_sid_range_add(prev, ep, size)) {
+ YLMSG_E("Adding a range into the .sid file \"%s\" failed.", yo->sid_prev_path);
+ goto cleanup;
+ }
+ if (yo->interactive) {
+ /* standalone range-add prints the previous file with the added range */
+ sid_file = prev;
+ prev = NULL;
+ }
+ }
+
+ if (!sid_file) {
+ assert(mod);
+ if (prev) {
+ /* update */
+ if (lys_sid_update(mod, prev, status, NULL, &sid_file)) {
+ YLMSG_E("Updating the .sid file of module \"%s\" failed.", mod->name);
+ goto cleanup;
+ }
+ } else {
+ /* generation */
+ if (lys_sid_gen(mod, ep, size, status, NULL, &sid_file)) {
+ YLMSG_E("Generating the .sid file for module \"%s\" failed.", mod->name);
+ goto cleanup;
+ }
+ }
+ }
+
+ rc = sid_print(yo, sid_file);
+
+cleanup:
+ free(name);
+ lyd_free_all(prev);
+ lyd_free_all(sid_file);
+ return rc;
+}
diff --git a/tools/lint/completion.c b/tools/lint/completion.c
index 78d8a267d7..e5a0b3a712 100644
--- a/tools/lint/completion.c
+++ b/tools/lint/completion.c
@@ -413,6 +413,17 @@ get_data_in_format_arg(const char *hint, char ***matches, unsigned int *match_co
get_arg_completion(hint, args, matches, match_count);
}
+/**
+ * @copydoc get_print_format_arg
+ */
+static void
+get_data_out_format_arg(const char *hint, char ***matches, unsigned int *match_count)
+{
+ const char *args[] = {"json", "xml", NULL};
+
+ get_arg_completion(hint, args, matches, match_count);
+}
+
/**
* @copydoc get_print_format_arg
*/
@@ -518,6 +529,9 @@ complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc)
{CMD_DATA, NULL, NULL},
{CMD_LIST, NULL, get_list_format_arg},
{CMD_FEATURE, NULL, get_model_completion},
+ {CMD_SID, "-o", NULL},
+ {CMD_SID, "-f", get_data_out_format_arg},
+ {CMD_SID, NULL, get_model_completion},
{CMD_VERB, NULL, get_verb_arg},
{CMD_DEBUG, NULL, get_debug_arg},
};
diff --git a/tools/lint/ietf.c b/tools/lint/ietf.c
new file mode 100644
index 0000000000..a44a7928d9
--- /dev/null
+++ b/tools/lint/ietf.c
@@ -0,0 +1,1051 @@
+/**
+ * @file ietf.c
+ * @author Petr Hanzlik
+ * @brief 'ietf' command of the libyang's yanglint tool.
+ *
+ * Copyright (c) 2026 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 _GNU_SOURCE
+
+#include "common.h"
+#include "ietf.h"
+#include "yl_opt.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "libyang.h"
+
+/* Global variable to track the return code of the IETF validation process. It is set to 1 if any IETF compliance issues are found during the checks. */
+static int rc = 0;
+
+#define IETF_RFC_VERSION "9907"
+
+#define IETF_WARN(file_name, rfc, section, out, ...) \
+ do { \
+ ly_print(out, "%s: warning: RFC %s: %s: ", file_name, rfc, section); \
+ ly_print(out, __VA_ARGS__); \
+ ly_print(out, "\n"); \
+ } while(0)
+
+#define IETF_ERR(file_name, rfc, section, out, ...) \
+ do { \
+ ly_print(out, "%s: error: RFC %s: %s: ", file_name, rfc, section); \
+ ly_print(out, __VA_ARGS__); \
+ ly_print(out, "\n"); \
+ } while(0)
+
+/**
+ * @brief Convert a file path to its base name.
+ *
+ * @param[in] filepath File path to convert.
+ * @return Base name of the file, or NULL if the input is invalid.
+ */
+const char *
+get_file_name(const char *filepath)
+{
+ const char *filename;
+
+ if (!filepath) {
+ return NULL;
+ }
+
+ filename = strrchr(filepath, '/');
+
+ if (filename) {
+ return filename + 1;
+ }
+ return filepath;
+}
+
+/**
+ * @brief Checks if a given text matches a specified regular expression pattern.
+ *
+ * @param[in] text Target string to search within. If NULL, the function returns 0.
+ * @param[in] pattern Pattern to match against.
+ * @return 1 if the pattern is successfully found within the text.
+ * @return 0 if the pattern is not found, if a compilation error occurs, or if invalid NULL arguments are passed.
+ */
+static int
+check_regex(const char *text, const char *pattern)
+{
+ if (!text || !pattern) {
+ return 0;
+ }
+
+ return ly_pattern_match(NULL, pattern, text, 0, NULL) == 0;
+}
+
+/**
+ * @brief Scans a description string for the presence of strict RFC 2119/8174 requirement keywords.
+ *
+ * @param[in] dsc Description text to evaluate.
+ * @return 1 if at least one RFC 2119 keyword is successfully found in the text.
+ * @return 0 if no keywords are found, if a compilation error occurs, or if NULL is passed.
+ */
+static int
+check_words(const char *dsc)
+{
+ const char *pattern;
+
+ /* Find a string that contains at least one of the strict RFC 2119 requirement words as a standalone word. */
+ pattern = ".*(^|[^a-zA-Z])(MUST|MUST NOT|REQUIRED|SHALL|SHALL NOT|SHOULD|SHOULD NOT|RECOMMENDED|NOT RECOMMENDED|MAY|OPTIONAL)([^a-zA-Z]|$).*";
+
+ if (!dsc) {
+ return 0;
+ }
+
+ return ly_pattern_match(NULL, pattern, dsc, 0, NULL) == 0;
+}
+
+/**
+ * @brief Helper to check a single XPath string for banned functions and axes.
+ *
+ * @param[in,out] out Libyang output handler where warnings and errors are printed.
+ * @param[in] xpath XPath string to check.
+ * @param[in] file_name Name of the file.
+ * @param[in] node_name Name of the node.
+ * @param[in] stmt Statement that contains the XPath string.
+ */
+static void
+check_xpath_string(struct ly_out *out, const char *xpath, const char *file_name, const char *node_name, const char *stmt)
+{
+ const char *func_pattern;
+ const char *axes_pattern;
+
+ if (!xpath) {
+ return;
+ }
+
+ /* W3C Regex for banned functions */
+ func_pattern = "((.|\\n)*[^a-zA-Z0-9_-])?(position|last|id|namespace-uri|name|lang|local-name)\\s*\\((.|\\n)*";
+ if (check_regex(xpath, func_pattern)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.6.2", out, "XPath function in \"%s\" statement on \"%s\" should not be used", stmt, node_name);
+ rc = 1;
+ }
+
+ /* W3C Regex for banned axes */
+ axes_pattern = "((.|\\n)*[^a-zA-Z0-9_-])?(preceding-sibling|following-sibling|preceding|following)\\s*::(.|\\n)*";
+ if (check_regex(xpath, axes_pattern)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.6.3", out, "XPath axis in \"%s\" statement on \"%s\" should not be used", stmt, node_name);
+ rc = 1;
+ }
+}
+
+/**
+ * @brief Helper to extract and check XPath strings from a node's 'when' and 'must' structures.
+ *
+ * @param[in,out] out Libyang output handler where warnings and errors are printed.
+ * @param[in] when Pointer to the structure containing the 'when' condition.
+ * @param[in] musts Array of structures containing 'must' conditions.
+ * @param[in] file_name Name of the file being checked.
+ * @param[in] node_name Name of the node being checked.
+ */
+static void
+check_node_xpath(struct ly_out *out, const struct lysp_when *when, const struct lysp_restr *musts, const char *file_name, const char *node_name)
+{
+ LY_ARRAY_COUNT_TYPE i;
+
+ /* Check 'when' condition */
+ if (when && when->cond) {
+ check_xpath_string(out, when->cond, file_name, node_name, "when");
+ }
+
+ /* Check all 'must' conditions */
+ if (musts) {
+ LY_ARRAY_FOR(musts, i) {
+ if (musts[i].arg.str) {
+ check_xpath_string(out, musts[i].arg.str, file_name, node_name, "must");
+ }
+ }
+ }
+}
+
+/**
+ * @brief Collapses all consecutive whitespace (newlines, tabs, spaces) into a single space.
+ * @param[in] input Input string.
+ * @return Normalized string.
+ */
+static char *
+normalize_whitespace(const char *input)
+{
+ size_t i, j = 0, len;
+ int in_whitespace = 0;
+
+ if (!input) {
+ return NULL;
+ }
+
+ len = strlen(input);
+ char *normalized = malloc(len + 1);
+
+ if (!normalized) {
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (isspace((unsigned char)input[i])) {
+ if (!in_whitespace) {
+ normalized[j++] = ' ';
+ in_whitespace = 1;
+ }
+ } else {
+ normalized[j++] = input[i];
+ in_whitespace = 0;
+ }
+ }
+ normalized[j] = '\0';
+ return normalized;
+}
+
+/**
+ * @brief Traverses the compiled schema tree to enforce IETF-specific validation rules.
+ *
+ * @param[in,out] out Libyang output handler where warnings and errors are printed.
+ * @param[in] data First top-level node of the compiled data tree to be inspected.
+ * @param[in] file_name Name of the file being evaluated (used to prefix the error messages).
+ */
+static void
+check_nodes_ietf(struct ly_out *out, const struct lysc_node *data, const char *file_name)
+{
+ const struct lysc_node *root, *elem;
+ char node_path[256];
+ int is_mandatory;
+
+ LY_LIST_FOR(data, root) {
+ is_mandatory = 0;
+
+ if ((root->flags & LYS_MAND_TRUE) && !(root->flags & LYS_CONFIG_R)) {
+ is_mandatory = 1;
+ }
+
+ if (is_mandatory) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.10", out, "top-level node \"%s\" must not be mandatory", root->name);
+ rc = 1;
+ }
+
+ LYSC_TREE_DFS_BEGIN(root, elem) {
+ lysc_path(elem, LYSC_PATH_LOG, node_path, sizeof(node_path));
+
+ if (elem->nodetype == LYS_CONTAINER) {
+ struct lysc_node_container *cont = (struct lysc_node_container *)elem;
+
+ if (cont->actions) {
+ check_nodes_ietf(out, (const struct lysc_node *)cont->actions, file_name);
+ }
+ if (cont->notifs) {
+ check_nodes_ietf(out, (const struct lysc_node *)cont->notifs, file_name);
+ }
+ } else if (elem->nodetype == LYS_LIST) {
+ struct lysc_node_list *list = (struct lysc_node_list *)elem;
+
+ if (list->actions) {
+ check_nodes_ietf(out, (const struct lysc_node *)list->actions, file_name);
+ }
+ if (list->notifs) {
+ check_nodes_ietf(out, (const struct lysc_node *)list->notifs, file_name);
+ }
+ }
+
+ switch (elem->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_LEAF:
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ case LYS_LEAFLIST:
+ case LYS_CHOICE:
+ case LYS_RPC:
+ if (!elem->dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"%s\" must have a \"description\" substatement", lys_nodetype2str(elem->nodetype));
+ rc = 1;
+ }
+ break;
+ case LYS_NOTIF:
+ if (!elem->dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14,4.16", out, "statement \"%s\" must have a \"description\" substatement", lys_nodetype2str(elem->nodetype));
+ rc = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ LYSC_TREE_DFS_END(root, elem);
+ }
+ }
+}
+
+/**
+ * @brief Helper function to validate locally scoped typedefs and groupings inside parsed data nodes.
+ *
+ * @param[in,out] out Libyang output handler for printing errors.
+ * @param[in] file_name Name of the parsed file for error prefixes.
+ * @param[in] typedefs Array of parsed typedefs to check.
+ * @param[in] groupings Linked list of parsed groupings to check.
+ * @param[in] node_type_str String literal representing the node type (e.g., "container", "list").
+ * @param[in] node_name String name of the parent node to provide context.
+ * @param[in,out] found_2119 Pointer to an integer flag that tracks if RFC 2119 keywords are used.
+ */
+static void
+check_inner_defs(struct ly_out *out, const char *file_name, struct lysp_tpdf *typedefs, struct lysp_node_grp *groupings, const char *node_type_str, const char *node_name, int *found_2119)
+{
+ LY_ARRAY_COUNT_TYPE i;
+ struct lysp_node_grp *grp;
+
+ LY_ARRAY_FOR(typedefs, i) {
+ if (strlen(typedefs[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", typedefs[i].name);
+ rc = 1;
+ }
+
+ if (!typedefs[i].dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.13,4.14", out,
+ "statement \"typedef\" inside %s \"%s\" must have a \"description\" substatement",
+ node_type_str, node_name);
+ rc = 1;
+ } else if (check_words(typedefs[i].dsc)) {
+ *found_2119 = 1;
+ }
+ }
+
+ LY_LIST_FOR(groupings, grp) {
+ if (strlen(grp->name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", grp->name);
+ rc = 1;
+ }
+
+ if (!grp->dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out,
+ "statement \"grouping\" inside %s \"%s\" must have a \"description\" substatement",
+ node_type_str, node_name);
+ rc = 1;
+ } else if (check_words(grp->dsc)) {
+ *found_2119 = 1;
+ }
+ }
+}
+
+/**
+ * @brief Recursively traverses and validates the parsed schema tree for IETF compliance.
+ *
+ * @param[in,out] out Libyang output handler where warnings and errors are printed.
+ * @param[in] node Starting node of the parsed data tree (or sibling list) to inspect.
+ * @param[in] file_name Name of the file being evaluated, used to prefix the log messages.
+ * @param[in,out] found_2119 Pointer to an integer flag used to record whether any node in this tree uses RFC 2119 keywords.
+ */
+static void
+check_parsed_tree_ietf(struct ly_out *out, const struct lysp_node *node, const char *file_name, int *found_2119)
+{
+ const struct lysp_node *elem;
+ LY_ARRAY_COUNT_TYPE i;
+
+ LY_LIST_FOR(node, elem) {
+ if (strlen(elem->name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", elem->name);
+ rc = 1;
+ }
+
+ if (elem->dsc && check_words(elem->dsc)) {
+ *found_2119 = 1;
+ }
+
+ if (elem->flags & LYS_CONFIG_W) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"config\" is given with its default value \"true\"");
+ rc = 1;
+ }
+
+ if (elem->flags & LYS_STATUS_CURR) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"status\" is given with its default value \"current\"");
+ rc = 1;
+ }
+
+ if (elem->flags & LYS_MAND_FALSE) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"mandatory\" is given with its default value \"false\"");
+ rc = 1;
+ }
+
+ if (elem->flags & LYS_ORDBY_SYSTEM) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"ordered-by\" is given with its default value \"system\"");
+ rc = 1;
+ }
+
+ switch (elem->nodetype) {
+ case LYS_CONTAINER: {
+ const struct lysp_node_container *cont = (struct lysp_node_container *)elem;
+
+ if ((elem->flags & LYS_CONFIG_R) && cont->musts) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.5", out, "constraints ('must' statements) on state data SHOULD be avoided (leaf \"%s\")", cont->name);
+ rc = 1;
+ }
+
+ check_node_xpath(out, cont->when, cont->musts, file_name, elem->name);
+ check_inner_defs(out, file_name, cont->typedefs, cont->groupings, "container", elem->name, found_2119);
+
+ if (cont->child) {
+ check_parsed_tree_ietf(out, cont->child, file_name, found_2119);
+ }
+ if (cont->actions) {
+ check_parsed_tree_ietf(out, (const struct lysp_node *)cont->actions, file_name, found_2119);
+ }
+ if (cont->notifs) {
+ check_parsed_tree_ietf(out, (const struct lysp_node *)cont->notifs, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_LIST: {
+ const struct lysp_node_list *list = (struct lysp_node_list *)elem;
+
+ check_node_xpath(out, list->when, list->musts, file_name, elem->name);
+ check_inner_defs(out, file_name, list->typedefs, list->groupings, "list", elem->name, found_2119);
+
+ if ((elem->flags & LYS_SET_MIN) && (list->min == 0)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"min-elements\" is given with its default value \"0\"");
+ rc = 1;
+ }
+
+ if ((elem->flags & LYS_SET_MAX) && (list->max == 0)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"max-elements\" is given with its default value \"unbounded\"");
+ rc = 1;
+ }
+
+ if ((elem->flags & LYS_CONFIG_R) && list->musts) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.5", out, "constraints ('must' statements) on state data should be avoided (leaf \"%s\")", list->name);
+ rc = 1;
+ }
+
+ if (list->child) {
+ check_parsed_tree_ietf(out, list->child, file_name, found_2119);
+ }
+ if (list->actions) {
+ check_parsed_tree_ietf(out, (const struct lysp_node *)list->actions, file_name, found_2119);
+ }
+ if (list->notifs) {
+ check_parsed_tree_ietf(out, (const struct lysp_node *)list->notifs, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_LEAFLIST: {
+ const struct lysp_node_leaflist *llist = (struct lysp_node_leaflist *)elem;
+
+ check_node_xpath(out, llist->when, llist->musts, file_name, elem->name);
+
+ if (!strcmp(llist->type.name, "empty")) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.5", out, "the type \"empty\" should not be used for a leaf-list (\"%s\")", llist->name);
+ rc = 1;
+ }
+
+ if ((elem->flags & LYS_CONFIG_R) && llist->musts) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.5", out, "constraints ('must' statements) on state data should be avoided (leaf \"%s\")", llist->name);
+ rc = 1;
+ }
+
+ if ((elem->flags & LYS_SET_MIN) && (llist->min == 0)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"min-elements\" is given with its default value \"0\"");
+ rc = 1;
+ }
+
+ if ((elem->flags & LYS_SET_MAX) && (llist->max == 0)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"max-elements\" is given with its default value \"unbounded\"");
+ rc = 1;
+ }
+
+ if (llist->type.enums) {
+ LY_ARRAY_FOR(llist->type.enums, i) {
+ if (strlen(llist->type.enums[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", llist->type.enums[i].name);
+ rc = 1;
+ }
+
+ if (!llist->type.enums[i].dsc) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.3", out, "statement \"enum\" should have a \"description\" substatement");
+ rc = 1;
+ }
+ }
+ }
+ if (llist->type.bits) {
+ LY_ARRAY_FOR(llist->type.bits, i) {
+ if (strlen(llist->type.bits[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", llist->type.bits[i].name);
+ rc = 1;
+ }
+
+ if (!llist->type.bits[i].dsc) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.3", out, "statement \"bit\" should have a \"description\" substatement");
+ rc = 1;
+ }
+ }
+ }
+ break;
+ }
+ case LYS_GROUPING: {
+ const struct lysp_node_grp *grp = (struct lysp_node_grp *)elem;
+
+ check_inner_defs(out, file_name, grp->typedefs, grp->groupings, "grouping", elem->name, found_2119);
+ if (grp->child) {
+ check_parsed_tree_ietf(out, grp->child, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_RPC:
+ case LYS_ACTION: {
+ const struct lysp_node_action *act = (struct lysp_node_action *)elem;
+ const char *type_str = (elem->nodetype == LYS_RPC) ? "rpc" : "action";
+
+ check_inner_defs(out, file_name, act->input.typedefs, act->input.groupings, type_str, elem->name, found_2119);
+
+ if (act->input.typedefs || act->input.groupings) {
+ check_inner_defs(out, file_name, act->input.typedefs, act->input.groupings, "input of", elem->name, found_2119);
+ }
+ if (act->input.child) {
+ check_parsed_tree_ietf(out, act->input.child, file_name, found_2119);
+ }
+
+ if (act->output.typedefs || act->output.groupings) {
+ check_inner_defs(out, file_name, act->output.typedefs, act->output.groupings, "output of", elem->name, found_2119);
+ }
+ if (act->output.child) {
+ check_parsed_tree_ietf(out, act->output.child, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_NOTIF: {
+ const struct lysp_node_notif *notif = (struct lysp_node_notif *)elem;
+
+ check_inner_defs(out, file_name, notif->typedefs, notif->groupings, "notification", elem->name, found_2119);
+ if (notif->child) {
+ check_parsed_tree_ietf(out, notif->child, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_CHOICE: {
+ const struct lysp_node_choice *choice = (struct lysp_node_choice *)elem;
+
+ check_node_xpath(out, choice->when, NULL, file_name, elem->name);
+
+ if (choice->child) {
+ check_parsed_tree_ietf(out, choice->child, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_CASE: {
+ const struct lysp_node_case *cas = (struct lysp_node_case *)elem;
+
+ check_node_xpath(out, cas->when, NULL, file_name, elem->name);
+
+ if (cas->child) {
+ check_parsed_tree_ietf(out, cas->child, file_name, found_2119);
+ }
+ break;
+ }
+ case LYS_LEAF: {
+ const struct lysp_node_leaf *leaf = (struct lysp_node_leaf *)elem;
+ const struct lysp_node_list *parent_list = (struct lysp_node_list *)elem->parent;
+ const struct lysp_node *parent_node = elem->parent;
+ LY_ARRAY_COUNT_TYPE leaf_iff_count;
+ LY_ARRAY_COUNT_TYPE list_iff_count;
+ int is_key = 0;
+
+ check_node_xpath(out, leaf->when, leaf->musts, file_name, elem->name);
+
+ if (elem->parent && (elem->parent->nodetype == LYS_LIST)) {
+ if (parent_list->key) {
+ if (!strcmp(parent_list->key, elem->name)) {
+ is_key = 1;
+ }
+ }
+ }
+
+ if ((elem->flags & LYS_CONFIG_R) && leaf->musts) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.5", out, "constraints ('must' statements) on state data should be avoided (leaf \"%s\")", leaf->name);
+ rc = 1;
+ }
+
+ if (is_key) {
+ if (leaf->when) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.5", out, "key leaf \"%s\" should not have a \"when\" statement", leaf->name);
+ rc = 1;
+ }
+
+ leaf_iff_count = elem->iffeatures ? LY_ARRAY_COUNT(elem->iffeatures) : 0;
+ list_iff_count = parent_node->iffeatures ? LY_ARRAY_COUNT(parent_node->iffeatures) : 0;
+
+ if (leaf_iff_count != list_iff_count) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.5", out, "key leaf \"%s\" must have the exact same \"if-feature\" statements as its parent list \"%s\"", leaf->name, parent_node->name);
+ rc = 1;
+ } else {
+ for (LY_ARRAY_COUNT_TYPE i = 0; i < list_iff_count; i++) {
+ if (strcmp(elem->iffeatures[i].str, parent_node->iffeatures[i].str)) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.5", out, "key leaf \"%s\" must have the exact same \"if-feature\" statements as its parent list \"%s\"", leaf->name, parent_node->name);
+ rc = 1;
+ break;
+ }
+ }
+ }
+
+ if (!strcmp(leaf->type.name, "empty")) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.5", out, "the type \"empty\" should not be used for a key leaf \"%s\"", leaf->name);
+ rc = 1;
+ }
+ }
+
+ if (!strcmp(leaf->type.name, "empty")) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.5", out, "in \"%s\", the \"boolean\" data type should be used instead of the \"empty\" data type", leaf->name);
+ }
+
+ if (leaf->type.enums) {
+ LY_ARRAY_FOR(leaf->type.enums, i) {
+ if (strlen(leaf->type.enums[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", leaf->type.enums[i].name);
+ rc = 1;
+ }
+
+ if (!leaf->type.enums[i].dsc) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.3", out, "statement \"enum\" should have a \"description\" substatement");
+ rc = 1;
+ }
+ }
+ }
+ if (leaf->type.bits) {
+ LY_ARRAY_FOR(leaf->type.bits, i) {
+ if (strlen(leaf->type.bits[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", leaf->type.bits[i].name);
+ rc = 1;
+ }
+
+ if (!leaf->type.bits[i].dsc) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.11.3", out, "statement \"bit\" should have a \"description\" substatement");
+ rc = 1;
+ }
+ }
+ }
+ break;
+ }
+ case LYS_USES: {
+ const struct lysp_node_uses *uses = (struct lysp_node_uses *)elem;
+ const struct lysp_node_augment *aug;
+
+ LY_LIST_FOR(uses->augments, aug) {
+ if (!aug->dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"augment\" inside uses \"%s\" must have a \"description\" substatement", uses->name);
+ rc = 1;
+ }
+
+ if (aug->child) {
+ check_parsed_tree_ietf(out, aug->child, file_name, found_2119);
+ }
+ }
+ break;
+ }
+ case LYS_ANYXML:
+ case LYS_ANYDATA: {
+ const struct lysp_node_anydata *anydata = (struct lysp_node_anydata *)elem;
+
+ check_node_xpath(out, anydata->when, anydata->musts, file_name, elem->name);
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * @brief Validates IETF-mandated boilerplate and top-level descriptions for a parsed module or submodule.
+ *
+ * @param[in] name Name of the module or submodule.
+ * @param[in] filepath File path of the module (used to prefix error messages).
+ * @param[in] dsc Top-level `description` text of the module/submodule.
+ * @param[in] contact Top-level `contact` text.
+ * @param[in] org Top-level `organization` text.
+ * @param[in] revs Pointer to the parsed `revision` array.
+ * @param[in] type Integer flag indicating whether the file is a module (0) or submodule (non-zero).
+ * @param[in] exts Array of top-level parsed `extension` statements.
+ * @param[in] feats Array of top-level parsed `feature` statements.
+ * @param[in] idents Array of top-level parsed `identity` statements.
+ * @param[in] augments Linked list of top-level parsed `augment` statements.
+ * @param[in] tpdfs Array of top-level parsed `typedef` statements.
+ * @param[in] grps Linked list of top-level parsed `grouping` statements.
+ * @param[in,out] out Libyang output handler where warnings and errors are printed.
+ * @param[in,out] found_2119 Pointer to a flag tracking if RFC 2119 keywords were found anywhere in this specific file.
+ */
+static void
+check_parsed_boilerplate(const char *name, const char *filepath, const char *dsc, const char *contact, const char *org, struct lysp_revision *revs, int type, struct lysp_ext *exts,
+ struct lysp_feature *feats, struct lysp_ident *idents, struct lysp_node_augment *augments, struct lysp_tpdf *tpdfs, struct lysp_node_grp *grps, struct ly_out *out, int *found_2119)
+{
+ const char *file_name = filepath ? get_file_name(filepath) : name;
+ const char *type_name = type ? "submodule" : "module";
+ const char *rfc8174_target, *tlp, *rfc_start, *tlp_part2;
+ char *norm_dsc, *endptr;
+ struct lysp_node_grp *grp;
+ struct lysp_node_augment *aug;
+ LY_ARRAY_COUNT_TYPE i;
+ int rfc_valid = 0, tlp_valid = 0, is_simplified;
+ long year;
+
+ if (strncmp(name, "ietf-", 5) && strncmp(name, "iana-", 5)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.1", out, "the module name should start with one of the strings \"ietf-\" or \"iana-\"");
+ rc = 1;
+ }
+
+ if (strlen(name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", name);
+ rc = 1;
+ }
+
+ if (!contact) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.8", out, "statement \"%s\" must have a \"contact\" substatement", type_name);
+ rc = 1;
+ }
+
+ if (!org) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.8", out, "statement \"%s\" must have a \"organization\" substatement", type_name);
+ rc = 1;
+ }
+
+ if (!revs) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.8", out, "statement \"%s\" must have a \"revision\" substatement", type_name);
+ rc = 1;
+ } else {
+ LY_ARRAY_FOR(revs, i) {
+ if (!revs[i].ref) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.8", out, "statement \"revision\" %s must have a \"reference\" substatement", revs[i].date);
+ rc = 1;
+ }
+ if (!revs[i].dsc) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.8", out, "statement \"revision\" %s should have a \"description\" substatement summarizing changes", revs[i].date);
+ rc = 1;
+ }
+ }
+ }
+
+ if (!dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.8", out, "statement \"%s\" must have a \"description\" substatement", type_name);
+ rc = 1;
+ return;
+ }
+
+ if (check_words(dsc)) {
+ *found_2119 = 1;
+ }
+
+ // Normalize whitespace for strict boilerplate matching
+ norm_dsc = normalize_whitespace(dsc);
+ if (!norm_dsc) {
+ ly_print(out, "%s: error: Memory allocation failed during description normalization.\n", file_name);
+ rc = 1;
+ return;
+ }
+
+ tlp = strstr(norm_dsc, "Copyright (c) ");
+ if (tlp) {
+ tlp += 14; // Skip past "Copyright (c) "
+
+ year = strtol(tlp, &endptr, 10);
+
+ if (tlp != endptr) {
+ tlp = endptr; // Move past the year
+ tlp_part2 =
+ " IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the ";
+
+ if (strncmp(tlp, tlp_part2, strlen(tlp_part2)) == 0) {
+ tlp += strlen(tlp_part2);
+ is_simplified = 0;
+
+ if (strncmp(tlp, "Revised", 7) == 0) {
+ tlp += 7;
+ } else if (strncmp(tlp, "Simplified", 10) == 0) {
+ is_simplified = 1;
+ tlp += 10;
+ }
+
+ // If we found Revised or Simplified, check the rest of the string
+ if (strncmp(tlp, " BSD License set forth in Section 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents (http", 107) == 0) {
+ tlp += 107;
+ if (*tlp == 's') {
+ tlp++; // allow https or http
+
+ }
+ if (strncmp(tlp, "://trustee.ietf.org/license-info).", 34) == 0) {
+ tlp_valid = 1;
+ // Throw error if they used "Simplified" in 2022 or later
+ if ((year >= 2022) && is_simplified) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "3.1", out, "The IETF Trust Copyright statement uses 'Simplified' instead of 'Revised' BSD License for a module >= 2022");
+ rc = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!tlp_valid) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "3.1", out, "The IETF Trust Copyright statement seems to be missing or is not correct");
+ rc = 1;
+ }
+
+ if (!strncmp(name, "ietf-", 5)) {
+ rfc_start = strstr(norm_dsc, "This version of this YANG module is part of RFC ");
+ if (!rfc_start) {
+ rfc_start = strstr(norm_dsc, "This version of this YANG submodule is part of RFC ");
+ }
+
+ if (rfc_start) {
+ // As long as the ending declaration exists anywhere after the start, it's valid
+ if (strstr(rfc_start, "; see the RFC itself for full legal notices.")) {
+ rfc_valid = 1;
+ }
+ }
+
+ if (!rfc_valid) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "Appendix B", out, "The text about which RFC this module is part of seems to be missing or is not correct");
+ rc = 1;
+ }
+ }
+
+ LY_ARRAY_FOR(exts, i) {
+ if (exts[i].flags & LYS_YINELEM_FALSE) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.4", out, "statement \"yin-element\" is given with its default value \"false\"");
+ rc = 1;
+ }
+
+ if (!exts[i].dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"%s\" must have a \"description\" substatement", "extension");
+ rc = 1;
+ } else if (check_words(exts[i].dsc)) {
+ *found_2119 = 1;
+ }
+ }
+
+ LY_ARRAY_FOR(feats, i) {
+ if (strlen(feats[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", feats[i].name);
+ rc = 1;
+ }
+
+ if (!feats[i].dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"%s\" must have a \"description\" substatement", "feature");
+ rc = 1;
+ } else if (check_words(feats[i].dsc)) {
+ *found_2119 = 1;
+ }
+ }
+
+ LY_ARRAY_FOR(idents, i) {
+ if (strlen(idents[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", idents[i].name);
+ rc = 1;
+ }
+
+ if (!idents[i].dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"%s\" must have a \"description\" substatement", "identity");
+ rc = 1;
+ } else if (check_words(idents[i].dsc)) {
+ *found_2119 = 1;
+ }
+ }
+
+ LY_LIST_FOR(augments, aug) {
+ if (!aug->dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"augment\" must have a \"description\" substatement");
+ rc = 1;
+ } else if (check_words(aug->dsc)) {
+ *found_2119 = 1;
+ }
+
+ if (aug->child) {
+ check_parsed_tree_ietf(out, aug->child, file_name, found_2119);
+ }
+ }
+
+ LY_ARRAY_FOR(tpdfs, i) {
+ if (strlen(tpdfs[i].name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", tpdfs[i].name);
+ rc = 1;
+ }
+
+ if (!tpdfs[i].dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.13,4.14", out, "statement \"typedef\" must have a \"description\" substatement");
+ rc = 1;
+ } else if (check_words(tpdfs[i].dsc)) {
+ *found_2119 = 1;
+ }
+ }
+
+ LY_LIST_FOR(grps, grp) {
+ if (strlen(grp->name) > 64) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.3", out, "identifier %s exceeds 64 characters", grp->name);
+ rc = 1;
+ }
+
+ if (!grp->dsc) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.14", out, "statement \"grouping\" must have a \"description\" substatement");
+ rc = 1;
+ } else if (check_words(grp->dsc)) {
+ *found_2119 = 1;
+ }
+ }
+
+ if (*found_2119) {
+ rfc8174_target =
+ "The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document are to be interpreted as described in BCP 14 (RFC 2119) (RFC 8174) when, and only when, they appear in all capitals, as shown here.";
+
+ if (!strstr(norm_dsc, rfc8174_target)) {
+ ly_print(out, "%s: warning: %s\n", file_name, "the module seems to use RFC 2119 keywords, but the required text from RFC 8174 is not found or is not correct");
+ rc = 1;
+ }
+ }
+
+ // Free the normalized string to prevent memory leaks
+ free(norm_dsc);
+}
+
+/**
+ * @brief Orchestrator for IETF RFC 9907 compliance validation on a YANG module.
+
+ * @param[in] mod Libyang module structure containing both the parsed schema
+ * @param[in,out] out Libyang output handler where compliance warnings and errors are printed.
+ */
+static void
+check_ietf(const struct lys_module *mod, struct ly_out *out)
+{
+ const char *file_name = mod->filepath ? get_file_name(mod->filepath) : mod->name;
+ const char *sub_file_name;
+ char ns[256];
+ LY_ARRAY_COUNT_TYPE i;
+ int main_found_2119 = 0;
+ struct lysp_submodule *sub;
+
+ if (mod->parsed->data) {
+ check_parsed_tree_ietf(out, mod->parsed->data, file_name, &main_found_2119);
+ }
+ if (mod->parsed->rpcs) {
+ check_parsed_tree_ietf(out, (struct lysp_node *)mod->parsed->rpcs, file_name, &main_found_2119);
+ }
+ if (mod->parsed->notifs) {
+ check_parsed_tree_ietf(out, (struct lysp_node *)mod->parsed->notifs, file_name, &main_found_2119);
+ }
+
+ check_parsed_boilerplate(mod->name, mod->filepath, mod->dsc, mod->contact, mod->org, mod->parsed->revs, mod->parsed->is_submod, mod->parsed->extensions, mod->parsed->features, mod->parsed->identities, mod->parsed->augments, mod->parsed->typedefs,
+ mod->parsed->groupings, out, &main_found_2119);
+
+ snprintf(ns, sizeof(ns), "urn:ietf:params:xml:ns:yang:%s", mod->name);
+ if (strcmp(ns, mod->ns)) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.9", out, "namespace value should be \"%s\"", ns);
+ rc = 1;
+ }
+
+ if (mod->parsed->imports) {
+ LY_ARRAY_FOR(mod->parsed->imports, i) {
+ if (!strncmp(mod->parsed->imports[i].name, "ietf-", 5) || !strncmp(mod->parsed->imports[i].name, "iana-", 5)) {
+ if (!mod->parsed->imports[i].ref) {
+ IETF_WARN(file_name, IETF_RFC_VERSION, "4.7", out, "statement \"import\" for stable module \"%s\" should have a \"reference\" substatement", mod->parsed->imports[i].name);
+ rc = 1;
+ }
+ }
+ }
+ }
+
+ if (mod->parsed->deviations) {
+ if (!strncmp(mod->name, "ietf-", 5) || !strncmp(mod->name, "iana-", 5)) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.20", out, "the YANG \"deviation\" statement is not allowed to appear in IETF YANG modules");
+ rc = 1;
+ }
+ }
+
+ LY_ARRAY_FOR(mod->parsed->includes, i) {
+ sub = mod->parsed->includes[i].submodule;
+ sub_file_name = sub->filepath ? get_file_name(sub->filepath) : sub->name;
+ int sub_found_2119 = 0;
+
+ if (mod->parsed->revs && sub->revs) {
+ if (strcmp(mod->parsed->revs[0].date, sub->revs[0].date) < 0) {
+ IETF_ERR(file_name, IETF_RFC_VERSION, "4.7", out, "the module's revision %s is older than submodule %s's revision %s", mod->parsed->revs[0].date, sub->name, sub->revs[0].date);
+ rc = 1;
+ }
+ }
+
+ if (sub->data) {
+ check_parsed_tree_ietf(out, sub->data, sub_file_name, &sub_found_2119);
+ }
+ if (sub->rpcs) {
+ check_parsed_tree_ietf(out, (struct lysp_node *)sub->rpcs, sub_file_name, &sub_found_2119);
+ }
+ if (sub->notifs) {
+ check_parsed_tree_ietf(out, (struct lysp_node *)sub->notifs, sub_file_name, &sub_found_2119);
+ }
+
+ check_parsed_boilerplate(sub->name, sub->filepath, sub->dsc, sub->contact, sub->org, sub->revs, sub->is_submod, sub->extensions, sub->features, sub->identities, sub->augments, sub->typedefs, sub->groupings, out, &sub_found_2119);
+ }
+
+ if (mod->compiled->data) {
+ check_nodes_ietf(out, mod->compiled->data, file_name);
+ }
+
+ if (mod->compiled->rpcs) {
+ check_nodes_ietf(out, (const struct lysc_node *)mod->compiled->rpcs, file_name);
+ }
+
+ if (mod->compiled->notifs) {
+ check_nodes_ietf(out, (const struct lysc_node *)mod->compiled->notifs, file_name);
+ }
+}
+
+int
+yl_validate_ietf(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv)
+{
+ const struct lys_module *mod;
+ char *revision, *name;
+ uint8_t out_alloc = 0;
+
+ name = strdup(posv);
+ if (!name) {
+ YLMSG_E("Memory allocation failed.");
+ return 1;
+ }
+ revision = strchr(name, '@');
+ if (revision) {
+ revision[0] = '\0';
+ ++revision;
+ }
+
+ mod = revision ?
+ ly_ctx_get_module(*ctx, name, revision) :
+ ly_ctx_get_module_latest(*ctx, name);
+
+ if (!mod || !mod->compiled || !mod->parsed) {
+ YLMSG_E("Error: Module %s not loaded or failed to compile.", name);
+ free(name);
+ return 1;
+ }
+
+ if (!yo->out) {
+ if (ly_out_new_file(stdout, &yo->out)) {
+ YLMSG_E("Unable to allocate output handler.");
+ free(name);
+ return 1;
+ }
+ out_alloc = 1;
+ }
+
+ check_ietf(mod, yo->out);
+
+ if (out_alloc) {
+ ly_out_free(yo->out, NULL, 0);
+ yo->out = NULL;
+ }
+
+ free(name);
+ return rc;
+}
diff --git a/tools/lint/ietf.h b/tools/lint/ietf.h
new file mode 100644
index 0000000000..701a3e56cf
--- /dev/null
+++ b/tools/lint/ietf.h
@@ -0,0 +1,32 @@
+/**
+ * @file ietf.h
+ * @author Petr Hanzlik
+ * @brief yanglint ietf header
+ *
+ * Copyright (c) 2026 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
+ */
+
+#ifndef IETF_H_
+#define IETF_H_
+
+#include "libyang.h"
+#include "yl_opt.h"
+
+/**
+ * @brief Validate a module against the IETF requirements.
+ *
+ * @param[in,out] ctx A double pointer to the libyang context containing the loaded modules.
+ * @param[in,out] yo A pointer to the yanglint options structure, which manages global
+ * @param[in] posv The positional command-line argument provided by the user, representing the target module name (e.g., "ietf-interfaces" or "ietf-interfaces@2014-05-08").
+ * @return 0 on successful execution of the validation pipeline (note: this returns 0 even if IETF compliance warnings/errors were printed to the output).
+ * @return 1 on fatal execution errors (e.g., module not found, module failed to compile, or memory allocation failure).
+ */
+int yl_validate_ietf(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
+
+#endif /* IETF_H_ */
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index dc83c9a861..e111840dd7 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -30,6 +30,7 @@
#include "cmd.h"
#include "common.h"
#include "compat.h"
+#include "ietf.h"
#include "out.h"
#include "tools/config.h"
#include "yl_opt.h"
@@ -52,6 +53,9 @@ help(int shortout)
" yanglint [-f { xml | json }] ... ...\n"
" Validates the YANG modeled data (s) according to the (s) optionally\n"
" printing them in the specified format.\n\n"
+ " yanglint -S { xml | json } ...\n"
+ " Generates and prints a sample data skeleton from the provided YANG (s)\n"
+ " in the specified format (XML or JSON).\n\n"
" yanglint -t (nc-)rpc/notif [-O ] ... \n"
" Validates the YANG/NETCONF RPC/notification according to the (s) using\n"
" with possible references to the operational datastore data.\n"
@@ -78,6 +82,10 @@ help(int shortout)
" yang, yin, tree, info and feature-param for schemas,\n"
" xml, json, and lyb for data.\n\n");
+ printf(" -S FORMAT, --sample-skeleton=FORMAT\n"
+ " Generate a sample data skeleton from the provided schema.\n"
+ " Supported formats: xml, json.\n\n");
+
printf(" -I FORMAT, --in-format=FORMAT\n"
" Load the data in one of the following formats:\n"
" xml, json, lyb\n"
@@ -218,6 +226,34 @@ help(int shortout)
printf(" -J, --json-null\n"
" Allow usage of JSON empty values ('null') within input data\n\n");
+ printf(" -T, --ietf\n"
+ " Enable stricter YANG model validation according to IETF rules.\n\n");
+
+ printf(" -g EP:SIZE, --sid-generate=EP:SIZE\n"
+ " Generate a new .sid file (RFC 9595) with the given SID assignment\n"
+ " range, print it. Only the last schema module given on the command\n"
+ " line is processed. The output format can be set by -f (default json).\n"
+ " EP (Entry Point) is the first SID of the new assignment range,\n"
+ " SIZE the number of SIDs to assign (must not be 0).\n\n");
+
+ printf(" -u FILE, --sid-update=FILE\n"
+ " Update an existing .sid file with the data of the currently processed\n"
+ " schema module, print it. Only the last schema module given on the\n"
+ " command line is processed. The output format can be set by -f\n"
+ " (default json).\n"
+ " Can be combined with --sid-range-add to add a new assignment\n"
+ " range into the updated file first.\n\n");
+
+ printf(" -r EP:SIZE, --sid-range-add=EP:SIZE\n"
+ " Add a new assignment range into the updated .sid file\n"
+ " (only in combination with --sid-update).\n"
+ " EP (Entry Point) is the first SID of the new assignment range,\n"
+ " SIZE the number of SIDs to assign (must not be 0).\n\n");
+
+ printf(" -U, --sid-publish\n"
+ " Generate/update the .sid file with the 'published' status\n"
+ " (otherwise 'unpublished').\n\n");
+
printf(" -G GROUPS, --debug=GROUPS\n"
#ifndef NDEBUG
" Enable printing of specific debugging message group\n"
@@ -410,6 +446,14 @@ process_files(int argc, char *argv[], int optind, LYD_FORMAT data_in_format, str
if (cmd_add_exec(&ctx, yo, filepath)) {
return -1;
}
+
+ if (yo->ietf_validation) {
+ struct lys_module *mod = (struct lys_module *)yo->schema_modules.objs[yo->schema_modules.count - 1];
+
+ if (yl_validate_ietf(&ctx, yo, mod->name)) {
+ return -1;
+ }
+ }
} else {
if (cmd_data_store(&ctx, yo, filepath)) {
return -1;
@@ -507,6 +551,12 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
{"extended-leafref", no_argument, NULL, 'X'},
{"json-null", no_argument, NULL, 'J'},
{"debug", required_argument, NULL, 'G'},
+ {"sample-skeleton", required_argument, NULL, 'S'},
+ {"ietf", no_argument, NULL, 'T'},
+ {"sid-generate", required_argument, NULL, 'g'},
+ {"sid-update", required_argument, NULL, 'u'},
+ {"sid-range-add", required_argument, NULL, 'r'},
+ {"sid-publish", no_argument, NULL, 'U'},
{NULL, 0, NULL, 0}
};
uint8_t data_type_set = 0;
@@ -518,7 +568,7 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
yo->line_length = 0;
opterr = 0;
- while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:At:d:lL:o:O:R:myY:XJx:G:", options, &opt_index)) != -1) {
+ while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:At:d:lL:o:O:R:myY:XJx:G:S:Tg:u:r:U", options, &opt_index)) != -1) {
switch (opt) {
case 'h': /* --help */
help(0);
@@ -711,6 +761,50 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
return -1;
}
break;
+
+ case 'S': /* --sample-skeleton */
+ if (yl_opt_update_data_out_format(optarg, yo)) {
+ YLMSG_E("Unknown out format %s.", optarg);
+ help(1);
+ return -1;
+ }
+ yo->sample_skeleton = 1;
+ break;
+
+ case 'T': /* --ietf */
+ yo->ietf_validation = 1;
+ break;
+
+ case 'g': /* --sid-generate */
+ case 'r': /* --sid-range-add */
+ if (yo->sid_range) {
+ YLMSG_E("The SID range option (--sid-generate/--sid-range-add) can be specified only once.");
+ return -1;
+ }
+ yo->sid_range = strdup(optarg);
+ if (!yo->sid_range) {
+ YLMSG_E("Memory allocation failed.");
+ return -1;
+ }
+ yo->sid_range_add = (opt == 'r');
+ break;
+
+ case 'u': /* --sid-update */
+ if (yo->sid_prev_path) {
+ YLMSG_E("The --sid-update option can be specified only once.");
+ return -1;
+ }
+ yo->sid_prev_path = strdup(optarg);
+ if (!yo->sid_prev_path) {
+ YLMSG_E("Memory allocation failed.");
+ return -1;
+ }
+ break;
+
+ case 'U': /* --sid-publish */
+ yo->sid_publish = 1;
+ break;
+
default:
YLMSG_E("Invalid option or missing argument: -%c.", optopt);
return -1;
@@ -730,6 +824,18 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
if (cmd_print_dep(yo, 0)) {
return -1;
}
+ if (yo->sid_publish && !yo->sid_range && !yo->sid_prev_path) {
+ YLMSG_E("The --sid-publish option requires --sid-generate or --sid-update.");
+ return -1;
+ }
+ if (yo->sid_range_add && !yo->sid_prev_path) {
+ YLMSG_E("The --sid-range-add option can be used only in combination with --sid-update.");
+ return -1;
+ }
+ if (yo->sid_prev_path && yo->sid_range && !yo->sid_range_add) {
+ YLMSG_E("The --sid-generate option cannot be combined with --sid-update, use --sid-range-add to add a range.");
+ return -1;
+ }
/* add the default search path */
search_path = getenv("YANGLINT_INTERNAL_MODULES_DIR");
@@ -818,6 +924,26 @@ main_ni(int argc, char *argv[])
goto cleanup;
}
}
+ } else if (yo.sample_skeleton) {
+ for (u = 0; u < yo.schema_modules.count; ++u) {
+ yo.last_one = (u + 1) == yo.schema_modules.count;
+ if ((ret = cmd_sample_exec(&ctx, &yo, ((struct lys_module *)yo.schema_modules.objs[u])->name))) {
+ goto cleanup;
+ }
+ }
+ } else if (yo.sid_range || yo.sid_prev_path) {
+ if (!yo.schema_modules.count) {
+ YLMSG_E("No schema module provided for the .sid file processing.");
+ ret = 1;
+ goto cleanup;
+ }
+
+ /* the .sid file is always generated/updated only for the last schema module
+ * given on the command line; all the other schema modules are loaded and
+ * validated, but they do not contribute to the .sid file processing */
+ if ((ret = cmd_sid_exec(&ctx, &yo, ((struct lys_module *)yo.schema_modules.objs[yo.schema_modules.count - 1])->name))) {
+ goto cleanup;
+ }
}
/* do the data validation despite the schema was printed */
diff --git a/tools/lint/yl_opt.c b/tools/lint/yl_opt.c
index 9912014b7e..771f883ed2 100644
--- a/tools/lint/yl_opt.c
+++ b/tools/lint/yl_opt.c
@@ -86,6 +86,10 @@ yl_opt_erase(struct yl_opt *yo)
/* context */
free(yo->searchpaths);
+ /* .sid file processing */
+ free(yo->sid_range);
+ free(yo->sid_prev_path);
+
/* --reply-rpc */
ly_in_free(yo->reply_rpc.in, 1);
diff --git a/tools/lint/yl_opt.h b/tools/lint/yl_opt.h
index d66ae4de91..7b5f07bf06 100644
--- a/tools/lint/yl_opt.h
+++ b/tools/lint/yl_opt.h
@@ -18,6 +18,7 @@
#include "parser_data.h" /* enum lyd_type */
#include "printer_schema.h" /* LYS_OUTFORMAT */
#include "set.h" /* ly_set */
+#include "tree_schema.h" /* LYS_SID_FILE_STATUS */
/**
* @brief Data connected with a file provided on a command line as a file path.
@@ -137,6 +138,27 @@ struct yl_opt {
/* storage for --data-xpath */
struct ly_set data_xpath;
+ /* flag for --ietf option */
+ uint8_t ietf_validation;
+
+ /* flag for --sample*/
+ uint8_t sample_skeleton;
+
+ /*
+ * .sid file processing (RFC 9595)
+ */
+ /* SID assignment range in the EP:SIZE format (generation or range addition) */
+ char *sid_range;
+
+ /* the range was provided by --sid-range-add (to be combined with --sid-update), not --sid-generate */
+ uint8_t sid_range_add;
+
+ /* generate/update the .sid file with the 'published' status */
+ uint8_t sid_publish;
+
+ /* path to the previous .sid file (update/range-add input) */
+ char *sid_prev_path;
+
char **argv;
};