schemas FEATURE add schema getters from the context

Also check for the duplicities in the context when parsing a new schema.
diff --git a/src/common.c b/src/common.c
index ab3b71f..dab8288 100644
--- a/src/common.c
+++ b/src/common.c
@@ -11,8 +11,8 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
-#define _XOPEN_SOURCE
-#define _DEFAULT_SOURCE
+
+#include "common.h"
 
 #include <assert.h>
 #include <errno.h>
@@ -25,7 +25,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "common.h"
 #include "tree_schema.h"
 
 const char *const ly_stmt_list[] = {
diff --git a/src/common.h b/src/common.h
index d7d17de..afd4d0b 100644
--- a/src/common.h
+++ b/src/common.h
@@ -15,6 +15,10 @@
 #ifndef LY_COMMON_H_
 #define LY_COMMON_H_
 
+#define _DEFAULT_SOURCE
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE
+
 #include <assert.h>
 #include <pthread.h>
 #include <stdint.h>
diff --git a/src/context.c b/src/context.c
index 1216704..ff6dc84 100644
--- a/src/context.c
+++ b/src/context.c
@@ -12,7 +12,8 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
-#define _DEFAULT_SOURCE
+#include "common.h"
+
 #define _BSD_SOURCE
 #include <errno.h>
 #include <limits.h>
@@ -23,7 +24,6 @@
 #include <unistd.h>
 
 #include "context.h"
-#include "common.h"
 #include "tree_schema_internal.h"
 #include "libyang.h"
 
@@ -261,6 +261,187 @@
     return ctx->module_set_id;
 }
 
+/**
+ * @brief Iterate over the modules in the given context. Returned modules must match the given key at the offset of
+ * lysp_module and lysc_module structures (they are supposed to be placed at the same offset in both structures).
+ *
+ * @param[in] ctx Context where to iterate.
+ * @param[in] key Key value to search for.
+ * @param[in] key_offset Key's offset in struct lysp_module and struct lysc_module to get value from the context's
+ * modules to match with the key.
+ * @param[in,out] Iterator to pass between the function calls. On the first call, the variable is supposed to be
+ * initiated to 0. After each call returning a module, the value is greater by 1 than the index of the returned
+ * module in the context.
+ * @return Module matching the given key, NULL if no such module found.
+ */
+static const struct lys_module *
+ly_ctx_get_module_by_iter(const struct ly_ctx *ctx, const char *key, size_t key_offset, unsigned int *index)
+{
+    const struct lys_module *mod;
+    const char *value;
+
+    for (; *index < ctx->list.count; ++(*index)) {
+        mod = ctx->list.objs[*index];
+        if (mod->compiled) {
+            value = *(const char**)(((int8_t*)(mod->compiled)) + key_offset);
+        } else {
+            value = *(const char**)(((int8_t*)(mod->parsed)) + key_offset);
+        }
+        if (!strcmp(key, value)) {
+            /* increment index for the next run */
+            ++(*index);
+            return mod;
+        }
+    }
+    /* done */
+    return NULL;
+}
+
+/**
+ * @brief Unifying function for ly_ctx_get_module() and ly_ctx_get_module_ns()
+ * @param[in] ctx Context where to search.
+ * @param[in] key Name or Namespace as a search key.
+ * @param[in] key_offset Key's offset in struct lysp_module to get value from the context's modules to match with the key.
+ * @param[in] revision Revision date to match. If NULL, the matching module must have no revision. To search for the latest
+ * revision module, use ly_ctx_get_module_latest_by().
+ * @return Matching module if any.
+ */
+static const struct lys_module *
+ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, size_t key_offset, const char *revision)
+{
+    const struct lys_module *mod;
+    unsigned int index = 0;
+
+    while ((mod = ly_ctx_get_module_by_iter(ctx, key, key_offset, &index))) {
+        if (!revision) {
+            if ((mod->compiled && !mod->compiled->revs) || (!mod->compiled && !mod->parsed->revs)) {
+                /* found requested module without revision */
+                return mod;
+            }
+        } else {
+            if ((mod->compiled && mod->compiled->revs && !strcmp(mod->compiled->revs[0].date, revision)) ||
+                    (!mod->compiled && mod->parsed->revs && !strcmp(mod->parsed->revs[0].date, revision))) {
+                /* found requested module of the specific revision */
+                return mod;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+API const struct lys_module *
+ly_ctx_get_module_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, ns, NULL);
+    return ly_ctx_get_module_by(ctx, ns, offsetof(struct lysp_module, ns), revision);
+}
+
+API const struct lys_module *
+ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
+    return ly_ctx_get_module_by(ctx, name, offsetof(struct lysp_module, name), revision);
+}
+
+/**
+ * @brief Unifying function for ly_ctx_get_module_latest() and ly_ctx_get_module_latest_ns()
+ * @param[in] ctx Context where to search.
+ * @param[in] key Name or Namespace as a search key.
+ * @param[in] key_offset Key's offset in struct lysp_module to get value from the context's modules to match with the key.
+ * @return Matching module if any.
+ */
+static const struct lys_module *
+ly_ctx_get_module_latest_by(const struct ly_ctx *ctx, const char *key, size_t key_offset)
+{
+    const struct lys_module *mod, *newest = NULL;
+    unsigned int index = 0;
+    const char *date, *date_newest = NULL;
+
+    while ((mod = ly_ctx_get_module_by_iter(ctx, key, key_offset, &index))) {
+        if (!newest) {
+            newest = mod;
+        } else {
+            if ((newest->compiled && !newest->compiled->revs) || (!newest->compiled && !newest->parsed->revs)) {
+                /* prefer modules with revisions, module with no revision
+                 * is supposed to be the oldest one */
+                newest = mod;
+                date_newest = NULL;
+            } else {
+                if (!date_newest) {
+                    if (newest->compiled) {
+                        date_newest = newest->compiled->revs[0].date;
+                    } else {
+                        date_newest = newest->parsed->revs[0].date;
+                    }
+                }
+                if (mod->compiled) {
+                    date = mod->compiled->revs[0].date;
+                } else {
+                    date = mod->parsed->revs[0].date;
+                }
+                if (strcmp(date, date_newest) > 0) {
+                    /* the current module is newer than so far newest, so remember it */
+                    newest = mod;
+                    date_newest = NULL;
+                }
+            }
+        }
+    }
+
+    return newest;
+}
+
+API const struct lys_module *
+ly_ctx_get_module_latest(const struct ly_ctx *ctx, const char *name)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
+    return ly_ctx_get_module_latest_by(ctx, name, offsetof(struct lysp_module, name));
+}
+
+const struct lys_module *
+ly_ctx_get_module_latest_ns(const struct ly_ctx *ctx, const char *ns)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, ns, NULL);
+    return ly_ctx_get_module_latest_by(ctx, ns, offsetof(struct lysp_module, ns));
+}
+
+/**
+ * @brief Unifying function for ly_ctx_get_module_implemented() and ly_ctx_get_module_implemented_ns()
+ * @param[in] ctx Context where to search.
+ * @param[in] key Name or Namespace as a search key.
+ * @param[in] key_offset Key's offset in struct lysp_module to get value from the context's modules to match with the key.
+ * @return Matching module if any.
+ */
+static const struct lys_module *
+ly_ctx_get_module_implemented_by(const struct ly_ctx *ctx, const char *key, size_t key_offset)
+{
+    const struct lys_module *mod;
+    unsigned int index = 0;
+
+    while ((mod = ly_ctx_get_module_by_iter(ctx, key, key_offset, &index))) {
+        if ((mod->compiled && mod->compiled->implemented) || (!mod->compiled && mod->parsed->implemented)) {
+            return mod;
+        }
+    }
+
+    return NULL;
+}
+
+API const struct lys_module *
+ly_ctx_get_module_implemented(const struct ly_ctx *ctx, const char *name)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, name, NULL);
+    return ly_ctx_get_module_implemented_by(ctx, name, offsetof(struct lysp_module, name));
+}
+
+API const struct lys_module *
+ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, ns, NULL);
+    return ly_ctx_get_module_implemented_by(ctx, ns, offsetof(struct lysp_module, ns));
+}
+
 API void
 ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lysc_node *node, void *priv))
 {
diff --git a/src/context.h b/src/context.h
index a172417..2333bb3 100644
--- a/src/context.h
+++ b/src/context.h
@@ -152,6 +152,72 @@
 uint16_t ly_ctx_get_module_set_id(const struct ly_ctx *ctx);
 
 /**
+ * @brief Get YANG module of the given name and revision.
+ *
+ * @param[in] ctx Context to work in.
+ * @param[in] name Name of the YANG module to get.
+ * @param[in] revision Requested revision date of the YANG module to get. If not specified,
+ * the schema with no revision is returned, if it is present in the context.
+ * @return Pointer to the YANG module, NULL if no schema in the context follows the name and revision requirements.
+ */
+const struct lys_module *ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision);
+
+/**
+ * @brief Get the latest revision of the YANG module specified by its name.
+ *
+ * YANG modules with no revision are supposed to be the oldest one.
+ *
+ * @param[in] ctx Context where to search.
+ * @param[in] name Name of the YANG module to get.
+ * @return The latest revision of the specified YANG module in the given context, NULL if no YANG module of the
+ * given name is present in the context.
+ */
+const struct lys_module *ly_ctx_get_module_latest(const struct ly_ctx *ctx, const char *name);
+
+/**
+ * @brief Get the (only) implemented YANG module specified by its name.
+ *
+ * @param[in] ctx Context where to search.
+ * @param[in] name Name of the YANG module to get.
+ * @return The only implemented YANG module revision of the given name in the given context. NULL if there is no
+ * implemented module of the given name.
+ */
+const struct lys_module *ly_ctx_get_module_implemented(const struct ly_ctx *ctx, const char *name);
+
+/**
+ * @brief Get YANG module of the given namespace and revision.
+ *
+ * @param[in] ctx Context to work in.
+ * @param[in] ns Namespace of the YANG module to get.
+ * @param[in] revision Requested revision date of the YANG module to get. If not specified,
+ * the schema with no revision is returned, if it is present in the context.
+ * @return Pointer to the YANG module, NULL if no schema in the context follows the namespace and revision requirements.
+ */
+const struct lys_module *ly_ctx_get_module_ns(const struct ly_ctx *ctx, const char *ns, const char *revision);
+
+/**
+ * @brief Get the latest revision of the YANG module specified by its namespace.
+ *
+ * YANG modules with no revision are supposed to be the oldest one.
+ *
+ * @param[in] ctx Context where to search.
+ * @param[in] ns Namespace of the YANG module to get.
+ * @return The latest revision of the specified YANG module in the given context, NULL if no YANG module of the
+ * given namespace is present in the context.
+ */
+const struct lys_module *ly_ctx_get_module_latest_ns(const struct ly_ctx *ctx, const char *ns);
+
+/**
+ * @brief Get the (only) implemented YANG module specified by its namespace.
+ *
+ * @param[in] ctx Context where to search.
+ * @param[in] ns Namespace of the YANG module to get.
+ * @return The only implemented YANG module revision of the given namespace in the given context. NULL if there is no
+ * implemented module of the given namespace.
+ */
+const struct lys_module *ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns);
+
+/**
  * @brief Free all internal structures of the specified context.
  *
  * The function should be used before terminating the application to destroy
diff --git a/src/log.c b/src/log.c
index 18d0b38..57da747 100644
--- a/src/log.c
+++ b/src/log.c
@@ -12,14 +12,14 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
-#define _GNU_SOURCE
+#include "common.h"
+
 #include <assert.h>
 #include <inttypes.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include "libyang.h"
-#include "common.h"
 #include "context.h"
 
 THREAD_LOCAL enum int_log_opts log_opt;
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 434073d..7ea75c6 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -1424,7 +1424,7 @@
         return LY_EVALID;
     }
 
-    strncpy(rev->rev, word, word_len);
+    strncpy(rev->date, word, word_len);
     free(buf);
 
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 3960bb3..60bd9b9 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -11,7 +11,8 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
-#define _DEFAULT_SOURCE
+
+#include "common.h"
 
 #include <ctype.h>
 #include <errno.h>
@@ -24,7 +25,6 @@
 #include <unistd.h>
 
 #include "libyang.h"
-#include "common.h"
 #include "context.h"
 #include "tree_schema_internal.h"
 
@@ -1076,7 +1076,7 @@
     return ret;
 }
 
-const struct lys_module *
+static const struct lys_module *
 lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
 {
     struct lys_module *mod = NULL;
@@ -1103,21 +1103,36 @@
     }
 
     if (implement) {
+        if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
+            LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
+            lys_module_free(mod, NULL);
+            return NULL;
+        }
         mod->parsed->implemented = 1;
     }
 
     if (revision) {
         /* check revision of the parsed model */
-        if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].rev)) {
+        if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
             LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
-                   mod->parsed->name, mod->parsed->revs[0].rev, revision);
-            lysp_module_free(mod->parsed);
-            free(mod);
+                   mod->parsed->name, mod->parsed->revs[0].date, revision);
+            lys_module_free(mod, NULL);
             return NULL;
         }
     }
 
     /* check for duplicity in the context */
+    if (ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL)) {
+        if (mod->parsed->revs) {
+            LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
+                   mod->parsed->name, mod->parsed->revs[0].date);
+        } else {
+            LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
+                   mod->parsed->name);
+        }
+        lys_module_free(mod, NULL);
+        return NULL;
+    }
 
     /* add into context */
     ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
@@ -1238,9 +1253,9 @@
     }
     if (rev) {
         len = dot - ++rev;
-        if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].rev, rev, len)) {
+        if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
             LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
-                   mod->parsed->revs ? mod->parsed->revs[0].rev : "none");
+                   mod->parsed->revs ? mod->parsed->revs[0].date : "none");
         }
     }
 
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 12394eb..3b939ea 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -308,7 +308,7 @@
  * @brief YANG revision-stmt
  */
 struct lysp_revision {
-    char rev[LY_REV_SIZE];           /**< revision date (madatory) */
+    char date[LY_REV_SIZE];           /**< revision date (madatory) */
     const char *dsc;                 /**< description statement */
     const char *ref;                 /**< reference statement */
     struct lysp_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
@@ -739,7 +739,6 @@
 struct lysp_module {
     struct ly_ctx *ctx;              /**< libyang context of the module (mandatory) */
     const char *name;                /**< name of the module (mandatory) */
-    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
     union {
         /* module */
         const char *ns;              /**< namespace of the module (module - mandatory) */
@@ -747,14 +746,15 @@
         const char *belongsto;       /**< belongs to parent module (submodule - mandatory) */
     };
     const char *prefix;              /**< module prefix or submodule belongsto prefix of main module (mandatory) */
+    struct lysp_revision *revs;      /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
+                                          in the list is always the last (newest) revision of the module */
     struct lysp_import *imports;     /**< list of imported modules ([sized array](@ref sizedarrays)) */
     struct lysp_include *includes;   /**< list of included submodules ([sized array](@ref sizedarrays)) */
+    const char *filepath;            /**< path, if the schema was read from a file, NULL in case of reading from memory */
     const char *org;                 /**< party/company responsible for the module */
     const char *contact;             /**< contact information for the module */
     const char *dsc;                 /**< description of the module */
     const char *ref;                 /**< cross-reference for the module */
-    struct lysp_revision *revs;      /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
-                                          in the list is always the last (newest) revision of the module */
     struct lysp_ext *extensions;     /**< list of extension statements ([sized array](@ref sizedarrays)) */
     struct lysp_feature *features;   /**< list of feature definitions ([sized array](@ref sizedarrays)) */
     struct lysp_ident *identities;   /**< list of identities ([sized array](@ref sizedarrays)) */
@@ -825,6 +825,14 @@
  */
 
 /**
+ * @brief Compiled YANG revision statement
+ */
+struct lysc_revision {
+    char date[LY_REV_SIZE];          /**< revision-date (mandatory) */
+    struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+};
+
+/**
  * @brief Compiled YANG if-feature-stmt
  */
 struct lysc_iffeature {
@@ -857,6 +865,8 @@
     const char *name;                /**< name of the module (mandatory) */
     const char *ns;                  /**< namespace of the module (mandatory) */
     const char *prefix;              /**< module prefix (mandatory) */
+    struct lysc_revision *revs;      /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
+                                          in the list is always the last (newest) revision of the module */
     struct lysc_import *imports;     /**< list of imported modules ([sized array](@ref sizedarrays)) */
 
 
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 0d0620c..b95505a 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -92,7 +92,7 @@
     struct lysp_revision rev;
 
     for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
-        if (strcmp(revs[i].rev, revs[r].rev) > 0) {
+        if (strcmp(revs[i].date, revs[r].date) > 0) {
             r = i;
         }
     }
diff --git a/tests/src/test_context.c b/tests/src/test_context.c
index d0fc202..992fdfa 100644
--- a/tests/src/test_context.c
+++ b/tests/src/test_context.c
@@ -14,6 +14,7 @@
 
 #include "tests/config.h"
 #include "../../src/context.c"
+#include "../../src/tree_schema.c"
 
 #include <stdarg.h>
 #include <stddef.h>
@@ -77,6 +78,7 @@
     struct ly_ctx *ctx;
     const char * const *list;
 
+    will_return_count(__wrap_ly_set_add, 0, 6);
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
 
     /* invalid arguments */
@@ -177,6 +179,8 @@
     (void) state; /* unused */
 
     struct ly_ctx *ctx;
+
+    will_return_always(__wrap_ly_set_add, 0);
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0xffffffff, &ctx));
 
     /* invalid arguments */
@@ -255,11 +259,13 @@
 {
     (void) state; /* unused */
 
+    struct ly_ctx *ctx;
+
     /* invalid arguments */
     assert_int_equal(0, ly_ctx_get_module_set_id(NULL));
     logbuf_assert("Invalid argument ctx (ly_ctx_get_module_set_id()).");
 
-    struct ly_ctx *ctx;
+    will_return_always(__wrap_ly_set_add, 0);
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
     assert_int_equal(ctx->module_set_id, ly_ctx_get_module_set_id(ctx));
 
@@ -267,12 +273,71 @@
     ly_ctx_destroy(ctx, NULL);
 }
 
+static void
+test_get_models(void **state)
+{
+    (void) state; /* unused */
+
+    struct ly_ctx *ctx;
+    const struct lys_module *mod, *mod2;
+    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-23;revision 2018-10-24;}";
+
+    will_return_always(__wrap_ly_set_add, 0);
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
+
+    /* invalid arguments */
+    assert_ptr_equal(NULL, ly_ctx_get_module(NULL, NULL, NULL));
+    logbuf_assert("Invalid argument ctx (ly_ctx_get_module()).");
+    assert_ptr_equal(NULL, ly_ctx_get_module(ctx, NULL, NULL));
+    logbuf_assert("Invalid argument name (ly_ctx_get_module()).");
+    assert_ptr_equal(NULL, ly_ctx_get_module_ns(NULL, NULL, NULL));
+    logbuf_assert("Invalid argument ctx (ly_ctx_get_module_ns()).");
+    assert_ptr_equal(NULL, ly_ctx_get_module_ns(ctx, NULL, NULL));
+    logbuf_assert("Invalid argument ns (ly_ctx_get_module_ns()).");
+    assert_null(ly_ctx_get_module(ctx, "nonsence", NULL));
+
+    /* internal modules */
+    assert_null(ly_ctx_get_module_implemented(ctx, "ietf-yang-types"));
+    mod = ly_ctx_get_module_implemented(ctx, "yang");
+    assert_non_null(mod);
+    assert_non_null(mod->parsed);
+    assert_string_equal("yang", mod->parsed->name);
+    mod2 = ly_ctx_get_module_implemented_ns(ctx, mod->parsed->ns);
+    assert_ptr_equal(mod, mod2);
+    assert_non_null(ly_ctx_get_module(ctx, "ietf-yang-metadata", "2016-08-05"));
+    assert_non_null(ly_ctx_get_module(ctx, "ietf-yang-types", "2013-07-15"));
+    assert_non_null(ly_ctx_get_module(ctx, "ietf-inet-types", "2013-07-15"));
+    assert_non_null(ly_ctx_get_module(ctx, "ietf-datastores", "2017-08-17"));
+
+    /* select module by revision */
+    mod = lys_parse_mem(ctx, str1, LYS_IN_YANG);
+    /* invalid attempts - implementing module of the same name and inserting the same module */
+    assert_null(lys_parse_mem(ctx, str2, LYS_IN_YANG));
+    logbuf_assert("Module \"a\" is already implemented in the context.");
+    assert_null(lys_parse_mem_(ctx, str1, LYS_IN_YANG, NULL, 0));
+    logbuf_assert("Module \"a\" of revision \"2018-10-23\" is already present in the context.");
+    /* insert the second module only as imported, not implemented */
+    mod2 = lys_parse_mem_(ctx, str2, LYS_IN_YANG, NULL, 0);
+    assert_non_null(mod);
+    assert_non_null(mod2);
+    assert_ptr_not_equal(mod, mod2);
+    mod = ly_ctx_get_module_latest(ctx, "a");
+    assert_ptr_equal(mod, mod2);
+    mod2 = ly_ctx_get_module_latest_ns(ctx, mod->parsed->ns);
+    assert_ptr_equal(mod, mod2);
+
+    /* cleanup */
+    ly_ctx_destroy(ctx, NULL);
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
         cmocka_unit_test_setup(test_searchdirs, logger_setup),
         cmocka_unit_test_setup(test_options, logger_setup),
         cmocka_unit_test_setup(test_models, logger_setup),
+        cmocka_unit_test_setup(test_get_models, logger_setup),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/src/test_hash_table.c b/tests/src/test_hash_table.c
index 1afeb83..05cd1f9 100644
--- a/tests/src/test_hash_table.c
+++ b/tests/src/test_hash_table.c
@@ -12,8 +12,7 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
-#define _BSD_SOURCE
-#define _DEFAULT_SOURCE
+#include "common.h"
 
 #include "tests/config.h"
 #include "../../src/hash_table.c"
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index db73f63..8f5085c 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -785,7 +785,7 @@
                  assert_string_equal("RFC7950", mod->ref));
     /* revision */
     TEST_GENERIC("revision 2018-10-12;}", mod->revs,
-                 assert_string_equal("2018-10-12", mod->revs[0].rev));
+                 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));
diff --git a/tests/src/test_set.c b/tests/src/test_set.c
index a6c53c4..982163f 100644
--- a/tests/src/test_set.c
+++ b/tests/src/test_set.c
@@ -11,9 +11,8 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
+#include "common.h"
 
-#define _BSD_SOURCE
-#define _DEFAULT_SOURCE
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>
diff --git a/tests/src/test_tree_schema_helpers.c b/tests/src/test_tree_schema_helpers.c
index 3dc7d7c..ac4e7bf 100644
--- a/tests/src/test_tree_schema_helpers.c
+++ b/tests/src/test_tree_schema_helpers.c
@@ -91,9 +91,9 @@
 
     /* revisions are stored in wrong order - the newest is the last */
     LY_ARRAY_NEW_RET(NULL, revs, rev,);
-    strcpy(rev->rev, "2018-01-01");
+    strcpy(rev->date, "2018-01-01");
     LY_ARRAY_NEW_RET(NULL, revs, rev,);
-    strcpy(rev->rev, "2018-12-31");
+    strcpy(rev->date, "2018-12-31");
 
     assert_int_equal(2, LY_ARRAY_SIZE(revs));
     assert_string_equal("2018-01-01", &revs[0]);
diff --git a/tests/src/test_xml.c b/tests/src/test_xml.c
index 568e55e..95d1302 100644
--- a/tests/src/test_xml.c
+++ b/tests/src/test_xml.c
@@ -12,8 +12,8 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
-#define _BSD_SOURCE
-#define _DEFAULT_SOURCE
+#include "common.h"
+
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>