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");