schema parsers FEATURE processing imports and includes
So far only in parsed structures, not the compiled.
diff --git a/src/context.c b/src/context.c
index 585504c..2394faf 100644
--- a/src/context.c
+++ b/src/context.c
@@ -449,7 +449,7 @@
}
LY_ARRAY_FOR(mod->parsed->includes, u) {
- if (!strcmp(submodule, mod->parsed->includes[u].submodule->name)) {
+ if (mod->parsed->includes[u].submodule && !strcmp(submodule, mod->parsed->includes[u].submodule->name)) {
inc = &mod->parsed->includes[u];
if (!revision) {
if (inc->submodule->latest_revision) {
diff --git a/src/context.h b/src/context.h
index 31493f2..b431587 100644
--- a/src/context.h
+++ b/src/context.h
@@ -161,9 +161,11 @@
* which were returned by this callback.
*
* @param[in] mod_name Missing module name.
- * @param[in] mod_rev Optional missing module revision.
+ * @param[in] mod_rev Optional missing module revision. If NULL and submod_name is not provided, the latest revision is
+ * requested, the parsed module is then marked by the latest_revision flag.
* @param[in] submod_name Optional missing submodule name.
- * @param[in] submod_rev Optional missing submodule revision.
+ * @param[in] submod_rev Optional missing submodule revision. If NULL and submod_name is provided, the latest revision is
+ * requested, the parsed submodule is then marked by the latest_revision flag.
* @param[in] user_data User-supplied callback data.
* @param[out] format Format of the returned module data.
* @param[out] module_data Requested module data.
diff --git a/src/parser_yang.c b/src/parser_yang.c
index c0ef806..5435eab 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -1293,7 +1293,6 @@
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
- const char *name = NULL;
size_t word_len;
enum yang_keyword kw;
struct lysp_include *inc;
@@ -1303,17 +1302,10 @@
/* get value */
ret = get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
LY_CHECK_RET(ret);
- INSERT_WORD(ctx, buf, name, word, word_len);
- ret = get_keyword(ctx, data, &kw, &word, &word_len);
- LY_CHECK_GOTO(ret, cleanup);
- LY_CHECK_GOTO(kw == YANG_SEMICOLON, parse_include);
- LY_CHECK_ERR_GOTO(kw != YANG_LEFT_BRACE,
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(kw));
- ret = LY_EVALID, cleanup);
- for (ret = get_keyword(ctx, data, &kw, &word, &word_len);
- !ret && (kw != YANG_RIGHT_BRACE);
- ret = get_keyword(ctx, data, &kw, &word, &word_len)) {
+ INSERT_WORD(ctx, buf, inc->name, word, word_len);
+
+ YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
switch (kw) {
case YANG_DESCRIPTION:
ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts);
@@ -1329,18 +1321,12 @@
break;
default:
LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
- lydict_remove(ctx->ctx, name);
return LY_EVALID;
}
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_RET(ret);
}
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_RET(ret);
-parse_include:
- ret = lysp_parse_include(ctx, mod, name, inc);
-
-cleanup:
- lydict_remove(ctx->ctx, name);
return ret;
}
@@ -1369,9 +1355,8 @@
LY_CHECK_RET(ret);
INSERT_WORD(ctx, buf, imp->name, word, word_len);
- YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
- LY_CHECK_RET(ret);
+ YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
switch (kw) {
case YANG_PREFIX:
ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts);
@@ -1398,10 +1383,7 @@
LY_CHECK_RET(ret);
/* mandatory substatements */
- if (!imp->prefix) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "import");
- return LY_EVALID;
- }
+ LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
return ret;
}
diff --git a/src/tree_schema.c b/src/tree_schema.c
index e058755..257a259 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -75,6 +75,7 @@
static void
lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import, int dict)
{
+ /* imported module is freed directly from the context's list */
FREE_STRING(ctx, import->name, dict);
FREE_STRING(ctx, import->prefix, dict);
FREE_STRING(ctx, import->dsc, dict);
@@ -88,6 +89,7 @@
if (include->submodule && !(--include->submodule->refcount)) {
lysp_module_free(include->submodule);
}
+ FREE_STRING(ctx, include->name, dict);
FREE_STRING(ctx, include->dsc, dict);
FREE_STRING(ctx, include->ref, dict);
FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
@@ -1080,13 +1082,15 @@
}
static void
-lys_latest_unset(struct lys_module *mod)
+lys_latest_switch(struct lys_module *old, struct lysp_module *new)
{
- if (mod->parsed) {
- mod->parsed->latest_revision = 0;
+ if (old->parsed) {
+ new->latest_revision = old->parsed->latest_revision;
+ old->parsed->latest_revision = 0;
}
- if (mod->compiled) {
- mod->compiled->latest_revision = 0;
+ if (old->compiled) {
+ new->latest_revision = old->parsed->latest_revision;
+ old->compiled->latest_revision = 0;
}
}
@@ -1095,7 +1099,10 @@
{
struct lys_module *mod = NULL, *latest;
struct lysp_module *latest_p;
+ struct lysp_import *imp;
+ struct lysp_include *inc;
LY_ERR ret;
+ unsigned int u, i;
LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
@@ -1147,17 +1154,17 @@
if (mod->parsed->revs) {
if (!latest_p->revs) {
/* latest has no revision, so mod is anyway newer */
- mod->parsed->latest_revision = 1;
+ mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
latest_p->latest_revision = 0;
} else {
if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
- mod->parsed->latest_revision = 1;
+ mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
latest_p->latest_revision = 0;
}
}
}
} else {
- mod->parsed->latest_revision = 1;
+ mod->parsed->latest_revision = revision ? 1 : 2;
}
} else { /* module */
/* check for duplicity in the context */
@@ -1193,12 +1200,10 @@
if (mod->parsed->revs) {
if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revs)) {
/* latest has no revision, so mod is anyway newer */
- mod->parsed->latest_revision = 1;
- lys_latest_unset(latest);
+ lys_latest_switch(latest, mod->parsed);
} else {
if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revs[0].date) > 0) {
- mod->parsed->latest_revision = 1;
- lys_latest_unset(latest);
+ lys_latest_switch(latest, mod->parsed);
}
}
}
@@ -1209,6 +1214,34 @@
/* add into context */
ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
+ /* resolve imports and includes */
+ mod->parsed->parsing = 1;
+ LY_ARRAY_FOR(mod->parsed->imports, u) {
+ imp = &mod->parsed->imports[u];
+ if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, &imp->module)) {
+ ly_set_rm(&ctx->list, mod, NULL);
+ lys_module_free(mod, NULL);
+ return NULL;
+ }
+ /* check for importing the same module twice */
+ for (i = 0; i < u; ++i) {
+ if (imp->module == mod->parsed->imports[i].module) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
+ ly_set_rm(&ctx->list, mod, NULL);
+ lys_module_free(mod, NULL);
+ return NULL;
+ }
+ }
+ }
+ LY_ARRAY_FOR(mod->parsed->includes, u) {
+ inc = &mod->parsed->includes[u];
+ if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
+ ly_set_rm(&ctx->list, mod, NULL);
+ lys_module_free(mod, NULL);
+ return NULL;
+ }
+ }
+ mod->parsed->parsing = 0;
}
return mod;
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 6bcbda1..048e87e 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -162,7 +162,9 @@
* @brief YANG import-stmt
*/
struct lysp_import {
- const char *name; /**< name of the module to import (mandatory) */
+ struct lys_module *module; /**< pointer to the imported module
+ (mandatory, but resolved when the referring module is completely parsed) */
+ const char *name; /**< name of the imported module (mandatory) */
const char *prefix; /**< prefix for the data from the imported schema (mandatory) */
const char *dsc; /**< description */
const char *ref; /**< reference */
@@ -174,7 +176,9 @@
* @brief YANG include-stmt
*/
struct lysp_include {
- struct lysp_module *submodule; /**< pointer to the parsed submodule structure (mandatory) */
+ struct lysp_module *submodule; /**< pointer to the parsed submodule structure
+ (mandatory, but resolved when the referring module is completely parsed) */
+ const char *name; /**< name of the included submodule (mandatory) */
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysp_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -769,9 +773,12 @@
uint8_t submodule:1; /**< flag to distinguish main modules and submodules */
uint8_t implemented:1; /**< flag if the module is implemented, not just imported */
- uint8_t latest_revision:1; /**< flag if the module was loaded without specific revision and is
- the latest revision found */
- uint8_t version:4; /**< yang-version (LYS_VERSION values) */
+ uint8_t latest_revision:2; /**< flag to mark the latest available revision:
+ 1 - the latest revision in searchdirs was not searched yet and this is the
+ latest revision in the current context
+ 2 - searchdirs were searched and this is the latest available revision */
+ uint8_t parsing:1; /**< flag for circular check */
+ uint8_t version; /**< yang-version (LYS_VERSION values) */
uint16_t refcount; /**< 0 in modules, number of includes of a submodules */
};
@@ -877,7 +884,7 @@
uint8_t implemented:1; /**< flag if the module is implemented, not just imported */
uint8_t latest_revision:1; /**< flag if the module was loaded without specific revision and is
the latest revision found */
- uint8_t version:4; /**< yang-version (LYS_VERSION values) */
+ uint8_t version; /**< yang-version (LYS_VERSION values) */
};
/**
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 746b7cb..a9bd79f 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -107,8 +107,102 @@
}
}
+void
+lys_module_implement(struct lys_module *mod)
+{
+ assert(mod);
+ if (mod->parsed) {
+ mod->parsed->implemented = 1;
+ }
+ if (mod->compiled) {
+ mod->compiled->implemented = 1;
+ }
+}
+
LY_ERR
-lysp_parse_include(struct ly_parser_ctx *ctx, struct lysp_module *mod, const char *name, struct lysp_include *inc)
+lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod)
+{
+ const char *submodule_data = NULL;
+ LYS_INFORMAT format = LYS_IN_UNKNOWN;
+ void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
+
+ /* try to get the module from the context */
+ if (revision) {
+ *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
+ } else {
+ *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
+ }
+
+ if (!(*mod)) {
+ /* check collision with other implemented revision */
+ if (implement && ly_ctx_get_module_implemented(ctx, name)) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+ "Module \"%s\" is already present in other implemented revision.", name);
+ return LY_EDENIED;
+ }
+
+ /* submodule not present in the context, get the input data and parse it */
+ if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+search_clb:
+ if (ctx->imp_clb) {
+ if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
+ &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
+ *mod = lys_parse_mem_(ctx, submodule_data, format, revision, implement);
+ }
+ }
+ if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ goto search_file;
+ }
+ } else {
+search_file:
+ if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+ /* module was not received from the callback or there is no callback set */
+ lys_module_localfile(ctx, name, revision, implement, mod);
+ }
+ if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ goto search_clb;
+ }
+ }
+ } else {
+ /* we have module from the current context */
+ if (implement && (ly_ctx_get_module_implemented(ctx, name) != *mod)) {
+ /* check collision with other implemented revision */
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
+ "Module \"%s\" is already present in other implemented revision.", name);
+ *mod = NULL;
+ return LY_EDENIED;
+ }
+
+ /* circular check */
+ if ((*mod)->parsed->parsing) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
+ *mod = NULL;
+ return LY_EVALID;
+ }
+ }
+ if (!(*mod)) {
+ if (ly_errcode(ctx) != LY_EVALID) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, strlen(name), name, "import");
+ } else {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Loading \"%s\" module failed.", name);
+ }
+ return LY_EVALID;
+ }
+
+ if (implement) {
+ /* mark the module implemented, check for collision was already done */
+ lys_module_implement(*mod);
+ }
+ if (!revision && ((*mod)->parsed->latest_revision == 1)) {
+ /* update the latest_revision flag - here we have selected the latest available schema */
+ (*mod)->parsed->latest_revision = 2;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
{
struct lys_module *submod;
const char *submodule_data = NULL;
@@ -116,30 +210,27 @@
void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
/* Try to get submodule from the context, if already present */
- inc->submodule = ly_ctx_get_submodule(ctx->ctx, mod->name, name, inc->rev[0] ? inc->rev : NULL);
+ inc->submodule = ly_ctx_get_submodule(ctx, mod->name, inc->name, inc->rev[0] ? inc->rev : NULL);
if (!inc->submodule) {
/* submodule not present in the context, get the input data and parse it */
- if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
search_clb:
- if (ctx->ctx->imp_clb) {
- if (ctx->ctx->imp_clb(mod->name, NULL, name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
+ if (ctx->imp_clb) {
+ if (ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
&format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
- submod = lys_parse_mem_(ctx->ctx, submodule_data, format, inc->rev[0] ? inc->rev : NULL, mod->implemented);
+ submod = lys_parse_mem_(ctx, submodule_data, format, inc->rev[0] ? inc->rev : NULL, mod->implemented);
}
}
- if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ if (!submod && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
goto search_file;
}
} else {
search_file:
- if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+ if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
/* module was not received from the callback or there is no callback set */
- lys_module_localfile(ctx->ctx, name, inc->rev[0] ? inc->rev : NULL, mod->implemented, &submod);
- if (inc->submodule) {
- ++inc->submodule->refcount;
- }
+ lys_module_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, &submod);
}
- if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ if (!submod && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
goto search_clb;
}
}
@@ -147,16 +238,24 @@
/* check that we have really a submodule */
if (!submod->parsed->submodule) {
/* submodule is not a submodule */
- LOGVAL_YANG(ctx, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.", name, mod->name);
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.",
+ inc->name, mod->name);
lys_module_free(submod, NULL);
/* fix list of modules in context, since it was already changed */
- --ctx->ctx->list.count;
+ --ctx->list.count;
return LY_EVALID;
}
/* check that the submodule belongs-to our module */
if (strcmp(mod->name, submod->parsed->belongsto)) {
- LOGVAL_YANG(ctx, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
- name, mod->name, submod->parsed->belongsto);
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
+ inc->name, mod->name, submod->parsed->belongsto);
+ lys_module_free(submod, NULL);
+ return LY_EVALID;
+ }
+ /* check circular dependency */
+ if (submod->parsed->parsing) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".",
+ submod->parsed->name);
lys_module_free(submod, NULL);
return LY_EVALID;
}
@@ -168,10 +267,10 @@
++inc->submodule->refcount;
}
if (!inc->submodule) {
- if (ly_errcode(ctx->ctx) != LY_EVALID) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, strlen(name), name, "include");
+ if (ly_errcode(ctx) != LY_EVALID) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Invalid value \"%s\" of include statement.", inc->name);
} else {
- LOGVAL_YANG(ctx, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", name, mod->name);
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
}
return LY_EVALID;
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 46727d4..58be352 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -75,16 +75,26 @@
void lysp_sort_revisions(struct lysp_revision *revs);
/**
+ * @brief Find and parse module of the given name.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] name Name of the module to load.
+ * @param[in] revison Optional revision of the module to load. If NULL, the newest revision is loaded.
+ * @param[out] mod Parsed module structure.
+ * @return LY_ERR value.
+ */
+LY_ERR lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod);
+
+/**
* @brief Parse included submodule into the simply parsed YANG module.
*
- * @param[in] ctx yang parser context.
+ * @param[in] ctx libyang context
* @param[in] mod Module including a submodule.
- * @param[in] name Name of the submodule to include.
* @param[in,out] inc Include structure holding all available information about the include statement, the parsed
* submodule is stored into this structure.
* @return LY_ERR value.
*/
-LY_ERR lysp_parse_include(struct ly_parser_ctx *ctx, struct lysp_module *mod, const char *name, struct lysp_include *inc);
+LY_ERR lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
/**
* @brief Find the module referenced by prefix in the provided mod.
@@ -170,6 +180,14 @@
* @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
*/
LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **result);
+
+/**
+ * @brief Make the module implemented.
+ * Does not check for collision in context, it must be done before calling the function, this is a simple switch.
+ * @param[in] mod Module to make implemented.
+ */
+void lys_module_implement(struct lys_module *mod);
+
/**
* @brief Free the schema structure. It just frees, it does not remove the schema from its context.
* @param[in,out] module Schema module structure to free.
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index e1e5891..8b3d7b9 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -762,36 +762,40 @@
TEST_GENERIC("identity test;}", mod->identities,
assert_string_equal("test", mod->identities[0].name));
/* import */
- TEST_GENERIC("import test {prefix z;}}", mod->imports,
- assert_string_equal("test", mod->imports[0].name));
+ ly_ctx_set_module_imp_clb(ctx.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 */
- str = SCHEMA_BEGINNING "import test {prefix x;}}";
+ str = SCHEMA_BEGINNING "import zzz {prefix x;}}";
assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
logbuf_assert("Prefix \"x\" already used as module prefix. Line number 2.");
mod = mod_renew(&ctx, mod, 0);
- str = SCHEMA_BEGINNING "import test1 {prefix y;}import test2 {prefix y;}}";
+ str = SCHEMA_BEGINNING "import zzz {prefix y;}import zzz {prefix y;}}";
assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
- logbuf_assert("Prefix \"y\" already used to import \"test1\" module. Line number 2.");
+ logbuf_assert("Prefix \"y\" already used to import \"zzz\" module. Line number 2.");
mod = mod_renew(&ctx, mod, 0);
+ str = "module" SCHEMA_BEGINNING "import zzz {prefix y;}import zzz {prefix z;}}";
+ assert_null(lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
+ assert_int_equal(LY_EVALID, ly_errcode(ctx.ctx));
+ logbuf_assert("Single revision of the module \"zzz\" referred twice.");
/* include */
ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "module xxx { namespace urn:xxx; prefix x;}");
- str = SCHEMA_BEGINNING "include xxx;}";
- assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
- logbuf_assert("Included \"xxx\" schema from \"name\" is actually not a submodule. Line number 2.");
- mod = mod_renew(&ctx, mod, 0);
+ str = "module" SCHEMA_BEGINNING "include xxx;}";
+ assert_null(lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
+ assert_int_equal(LY_EVALID, ly_errcode(ctx.ctx));
+ logbuf_assert("Included \"xxx\" schema from \"name\" is actually not a submodule.");
ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "submodule xxx {belongs-to wrong-name;}");
- str = SCHEMA_BEGINNING "include xxx;}";
- assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
- logbuf_assert("Included \"xxx\" submodule from \"name\" belongs-to a different module \"wrong-name\". Line number 2.");
- mod = mod_renew(&ctx, mod, 0);
+ str = "module" SCHEMA_BEGINNING "include xxx;}";
+ assert_null(lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
+ assert_int_equal(LY_EVALID, ly_errcode(ctx.ctx));
+ logbuf_assert("Included \"xxx\" submodule from \"name\" belongs-to a different module \"wrong-name\".");
ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "submodule xxx {belongs-to name;}");
TEST_GENERIC("include xxx;}", mod->includes,
- assert_non_null(mod->includes[0].submodule);
- assert_string_equal("xxx", mod->includes[0].submodule->name));
+ assert_string_equal("xxx", mod->includes[0].name));
/* leaf */
TEST_NODE(LYS_LEAF, "leaf test {type string;}}", "test");