yin parser CHANGE add support for deviate element
diff --git a/src/common.h b/src/common.h
index dc23869..05d4893 100644
--- a/src/common.h
+++ b/src/common.h
@@ -199,6 +199,7 @@
 #define LY_VCODE_INCHILDSTMT_YIN LYVE_SYNTAX_YIN, "Invalid element \"%.*s\" as a child of \"%.*s\"."
 #define LY_VCODE_MISSATTR    LYVE_SYNTAX_YIN, "Missing mandatory child element \"%s\" of %s element ."
 #define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected child element \"%.*s\" of %s element."
+#define LY_VCODE_INDEV_YIN   LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
 
 #define LY_VCODE_XP_EOE      LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
 #define LY_VCODE_XP_INEXPR   LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 4d75d66..805f5a6 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -1008,7 +1008,7 @@
                  enum yang_keyword parent, enum yang_keyword current, void *dest)
 {
     assert(current == YANG_MAX_ELEMENTS || current == YANG_MIN_ELEMENTS);
-    assert(parent == YANG_LEAF_LIST || parent == YANG_REFINE || parent == YANG_LIST);
+    assert(parent == YANG_LEAF_LIST || parent == YANG_REFINE || parent == YANG_LIST || parent == YANG_DEVIATE);
     uint32_t *lim;
     uint16_t *flags;
     struct lysp_ext_instance **exts;
@@ -1021,10 +1021,14 @@
         lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_refine *)dest)->max : &((struct lysp_refine *)dest)->min;
         flags = &((struct lysp_refine *)dest)->flags;
         exts = &((struct lysp_refine *)dest)->exts;
-    } else {
+    } else if (parent == YANG_LIST) {
         lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_node_list *)dest)->max : &((struct lysp_node_list *)dest)->min;
         flags = &((struct lysp_node_list *)dest)->flags;
         exts = &((struct lysp_node_list *)dest)->exts;
+    } else {
+        lim = ((struct minmax_dev_meta *)dest)->lim;
+        flags = ((struct minmax_dev_meta *)dest)->flags;
+        exts = ((struct minmax_dev_meta *)dest)->exts;
     }
 
     if (current == YANG_MAX_ELEMENTS) {
@@ -2039,6 +2043,113 @@
     return LY_SUCCESS;
 }
 
+static LY_ERR
+yin_parse_deviate(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct lysp_deviate **deviates)
+{
+    LY_ERR ret = LY_SUCCESS;
+    uint8_t dev_mod;
+    const char *temp_val;
+    struct lysp_deviate *iter, *d;
+    struct lysp_deviate_add *d_add = NULL;
+    struct lysp_deviate_rpl *d_rpl = NULL;
+    struct lysp_deviate_del *d_del = NULL;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_DEVIATE));
+
+    if (strcmp(temp_val, "not-supported") == 0) {
+        dev_mod = LYS_DEV_NOT_SUPPORTED;
+    } else if (strcmp(temp_val, "add") == 0) {
+        dev_mod = LYS_DEV_ADD;
+    } else if (strcmp(temp_val, "replace") == 0) {
+        dev_mod = LYS_DEV_REPLACE;
+    } else if (strcmp(temp_val, "delete") == 0) {
+        dev_mod = LYS_DEV_DELETE;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL, strlen(temp_val), temp_val, "deviate");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    if (dev_mod == LYS_DEV_NOT_SUPPORTED) {
+        d = calloc(1, sizeof *d);
+        LY_CHECK_ERR_RET(!d, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        struct yin_subelement subelems[1] = {
+                                                {YANG_CUSTOM, NULL, 0}
+                                            };
+        ret = yin_parse_content(ctx, subelems, 1, data, YANG_DEVIATE, NULL, &d->exts);
+
+    } else if (dev_mod == LYS_DEV_ADD) {
+        d_add = calloc(1, sizeof *d_add);
+        LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        d = (struct lysp_deviate *)d_add;
+        struct minmax_dev_meta min = {&d_add->min, &d_add->flags, &d_add->exts};
+        struct minmax_dev_meta max = {&d_add->max, &d_add->flags, &d_add->exts};
+        struct yin_subelement subelems[9] = {
+                                                {YANG_CONFIG, &d_add->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_DEFAULT, &d_add->dflts, 0},
+                                                {YANG_MANDATORY, &d_add->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MAX_ELEMENTS, &max, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MIN_ELEMENTS, &min, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MUST, &d_add->musts, 0},
+                                                {YANG_UNIQUE, &d_add->uniques, 0},
+                                                {YANG_UNITS, &d_add->units, YIN_SUBELEM_UNIQUE},
+                                                {YANG_CUSTOM, NULL, 0},
+                                            };
+        ret = yin_parse_content(ctx, subelems, 9, data, YANG_DEVIATE, NULL, &d_add->exts);
+
+    } else if (dev_mod == LYS_DEV_REPLACE) {
+        d_rpl = calloc(1, sizeof *d_rpl);
+        LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        d = (struct lysp_deviate *)d_rpl;
+        struct minmax_dev_meta min = {&d_rpl->min, &d_rpl->flags, &d_rpl->exts};
+        struct minmax_dev_meta max = {&d_rpl->max, &d_rpl->flags, &d_rpl->exts};
+        struct yin_subelement subelems[8] = {
+                                                {YANG_CONFIG, &d_rpl->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_DEFAULT, &d_rpl->dflt, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MANDATORY, &d_rpl->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MAX_ELEMENTS, &max, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MIN_ELEMENTS, &min, YIN_SUBELEM_UNIQUE},
+                                                {YANG_TYPE, &d_rpl->type, YIN_SUBELEM_UNIQUE},
+                                                {YANG_UNITS, &d_rpl->units, YIN_SUBELEM_UNIQUE},
+                                                {YANG_CUSTOM, NULL, 0},
+                                            };
+        ret = yin_parse_content(ctx, subelems, 8, data, YANG_DEVIATE, NULL, &d_rpl->exts);
+
+    } else {
+        d_del = calloc(1, sizeof *d_del);
+        LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        d = (struct lysp_deviate *)d_del;
+        struct yin_subelement subelems[5] = {
+                                                {YANG_DEFAULT, &d_del->dflts, 0},
+                                                {YANG_MUST, &d_del->musts, 0},
+                                                {YANG_UNIQUE, &d_del->uniques, 0},
+                                                {YANG_UNITS, &d_del->units, YIN_SUBELEM_UNIQUE},
+                                                {YANG_CUSTOM, NULL, 0},
+                                            };
+        ret = yin_parse_content(ctx, subelems, 5, data, YANG_DEVIATE, NULL, &d_del->exts);
+    }
+    LY_CHECK_GOTO(ret, cleanup);
+
+    d->mod = dev_mod;
+    /* insert into siblings */
+    if (!*deviates) {
+        *deviates = d;
+    } else {
+        for (iter = *deviates; iter->next; iter = iter->next);
+        iter->next = d;
+    }
+
+    return ret;
+
+cleanup:
+    free(d);
+    /* TODO log deviate error */
+    return ret;
+}
+
 /**
  * @brief Map keyword type to substatement info.
  *
@@ -2153,33 +2264,41 @@
                 /* check if this element can be child of current element */
                 subelem = get_record(kw, subelem_info_size, subelem_info);
                 if (!subelem) {
-                    LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name.len, name.value, ly_stmt2str(current_element));
+                    if (current_element == YANG_DEVIATE && isdevsub(kw)) {
+                        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INDEV_YIN, ly_stmt2str(kw));
+                    } else {
+                        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name.len, name.value, ly_stmt2str(current_element));
+                    }
                     ret = LY_EVALID;
                     goto cleanup;
                 }
 
                 /* TODO check relative order */
 
-                /* check flags */
-                /* if element is unique and already defined log error */
+                /* flag check */
                 if ((subelem->flags & YIN_SUBELEM_UNIQUE) && (subelem->flags & YIN_SUBELEM_PARSED)) {
+                    /* subelement uniquenes */
                     LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YIN, "Redefinition of %s element in %s element.", ly_stmt2str(kw), ly_stmt2str(current_element));
                     return LY_EVALID;
                 }
                 if (subelem->flags & YIN_SUBELEM_FIRST) {
+                    /* subelement is supposed to be defined as first subelement */
                     ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, current_element, subelem);
                     LY_CHECK_GOTO(ret, cleanup);
                 }
                 if (subelem->flags & YIN_SUBELEM_VER2) {
+                    /* subelement is supported only in version 1.1 or higher */
                     if (ctx->mod_version < 2) {
                         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVCODE_INSUBELEM2, ly_stmt2str(kw), ly_stmt2str(current_element));
                         ret = LY_EVALID;
                         goto cleanup;
                     }
                 }
+                /* note that element was parsed for easy uniqueness check in next iterations */
                 subelem->flags |= YIN_SUBELEM_PARSED;
 
                 switch (kw) {
+                /* call responsible function */
                 case YANG_CUSTOM:
                     ret = yin_parse_extension_instance(ctx, attrs, data, name2fullname(name.value, prefix.len),
                                                       namelen2fulllen(name.len, prefix.len),
@@ -2249,6 +2368,7 @@
                     }
                     break;
                 case YANG_DEVIATE:
+                    ret = yin_parse_deviate(ctx, attrs, data, (struct lysp_deviate **)subelem->dest);
                     break;
                 case YANG_DEVIATION:
                     break;
@@ -2380,8 +2500,14 @@
                 case YANG_SUBMODULE:
                     break;
                 case YANG_TYPE:
+                    if (current_element == YANG_DEVIATE) {
+                        *(struct lysp_type **)subelem->dest = calloc(1, sizeof **(struct lysp_type **)subelem->dest);
+                        LY_CHECK_ERR_GOTO(!(*(struct lysp_type **)subelem->dest), LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, cleanup);
+                        type = *((struct lysp_type **)subelem->dest);
+                    } else  {
+                        type = (struct lysp_type *)subelem->dest;
+                    }
                     /* type as child of another type */
-                    type = (struct lysp_type *)subelem->dest;
                     if (current_element == YANG_TYPE) {
                         LY_ARRAY_NEW_GOTO(ctx->xml_ctx.ctx, type->types, nested_type, ret, cleanup);
                         type->flags |= LYS_SET_TYPE;
@@ -2428,6 +2554,7 @@
         } else {
             /* elements with text or none content */
             /* save text content, if text_content isn't set, it's just ignored */
+            /* no resources are allocated in this branch so no need to use cleanup label */
             LY_CHECK_RET(yin_validate_value(ctx, Y_STR_ARG, out, out_len));
             if (text_content) {
                 if (dynamic) {
@@ -2448,6 +2575,7 @@
             LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix.value, &prefix.len, &name.value, &name.len));
         }
 
+        /* mandatory subelemnts are checked only after whole element was succesfully parsed */
         LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, current_element));
     }
 
@@ -2706,7 +2834,7 @@
                     /* end of extension instance reached */
                     break;
                 }
-                LY_CHECK_RET(yin_parse_element_generic(ctx, name, name_len, prefix, prefix_len, data, &new_subelem));
+                LY_CHECK_RET(yin_parse_element_generic(ctx, name, name_len, data, &new_subelem));
                 if (!e->child) {
                     e->child = new_subelem;
                 } else {
@@ -2735,13 +2863,13 @@
 }
 
 LY_ERR
-yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix,
-                          size_t prefix_len, const char **data, struct lysp_stmt **element)
+yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char **data,
+                          struct lysp_stmt **element)
 {
     LY_ERR ret = LY_SUCCESS;
     const char *temp_prefix, *temp_name;
     char *out = NULL;
-    size_t out_len, temp_name_len, temp_prefix_len;
+    size_t out_len, temp_name_len, temp_prefix_len, prefix_len;
     int dynamic;
     struct yin_arg_record *subelem_args = NULL;
     struct lysp_stmt *last = NULL, *new = NULL;
@@ -2800,7 +2928,7 @@
                 /* end of element reached */
                 break;
             }
-            ret = yin_parse_element_generic(ctx, temp_name, temp_name_len, temp_prefix, temp_prefix_len, data, &last->next);
+            ret = yin_parse_element_generic(ctx, temp_name, temp_name_len, data, &last->next);
             LY_CHECK_GOTO(ret, err);
             last = last->next;
         }
diff --git a/src/parser_yin.h b/src/parser_yin.h
index fca7c04..f6b0d6b 100644
--- a/src/parser_yin.h
+++ b/src/parser_yin.h
@@ -29,6 +29,14 @@
 #define name2fullname(name, prefix_len) (prefix_len != 0 ? name - (prefix_len + 1) : name)
 #define namelen2fulllen(name_len, prefix_len) (prefix_len != 0 ? name_len + prefix_len + 1 : name_len)
 
+/* shortcut to determin if keyword can in general be subelement of deviation regardles of it's type */
+#define isdevsub(kw) (kw == YANG_CONFIG || kw == YANG_DEFAULT || kw == YANG_MANDATORY || \
+                      kw == YANG_MAX_ELEMENTS || kw == YANG_MIN_ELEMENTS ||              \
+                      kw == YANG_MUST || kw == YANG_TYPE || kw == YANG_UNIQUE ||         \
+                      kw == YANG_UNITS || kw == YANG_CUSTOM)
+
+/* get deviate type from  */
+
 enum YIN_ARGUMENT {
     YIN_ARG_UNKNOWN = 0,   /**< parsed argument can not be matched with any supported yin argument keyword */
     YIN_ARG_NAME,          /**< argument name */
@@ -139,6 +147,12 @@
     struct lysp_action **actions;     /**< Actions to add to. */
 };
 
+struct minmax_dev_meta {
+    uint32_t *lim;
+    uint16_t *flags;
+    struct lysp_ext_instance **exts;
+};
+
 /**
  * @brief Match argument name.
  *
@@ -351,14 +365,12 @@
  * @param[in,out] ctx Yin parser context for logging and to store current state.
  * @param[in] name Name of element.
  * @param[in] name_len Length of elements Name.
- * @param[in] prefix Element prefix.
- * @param[in] prefix_len Length of element prefix.
  * @param[in,out] data Data to read from, always moved to currently handled character.
  * @param[out] element Where the element structure should be stored.
  *
  * @return LY_ERR values.
  */
-LY_ERR yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix,
-                                 size_t prefix_len, const char **data, struct lysp_stmt **element);
+LY_ERR yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char **data,
+                                 struct lysp_stmt **element);
 
 #endif /* LY_PARSER_YIN_H_*/
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
index b1fa9e8..6153792 100644
--- a/tests/src/test_parser_yin.c
+++ b/tests/src/test_parser_yin.c
@@ -44,6 +44,7 @@
 void lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout);
 void lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action);
 void lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment);
+void lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d);
 
 struct state {
     struct ly_ctx *ctx;
@@ -58,7 +59,7 @@
 int store = -1; /* negative for infinite logging, positive for limited logging */
 
 /* set to 0 to printing error messages to stderr instead of checking them in code */
-#define ENABLE_LOGGER_CHECKING 0
+#define ENABLE_LOGGER_CHECKING 1
 
 #if ENABLE_LOGGER_CHECKING
 static void
@@ -353,7 +354,7 @@
 
     const char *data = "<elem attr=\"value\">text_value</elem>";
     lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
-    ret = yin_parse_element_generic(st->yin_ctx, name, name_len, prefix, prefix_len, &data, &exts.child);
+    ret = yin_parse_element_generic(st->yin_ctx, name, name_len, &data, &exts.child);
     assert_int_equal(ret, LY_SUCCESS);
     assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
     assert_string_equal(exts.child->stmt, "elem");
@@ -366,7 +367,7 @@
 
     data = "<elem></elem>";
     lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
-    ret = yin_parse_element_generic(st->yin_ctx, name, name_len, prefix, prefix_len, &data, &exts.child);
+    ret = yin_parse_element_generic(st->yin_ctx, name, name_len, &data, &exts.child);
     assert_int_equal(ret, LY_SUCCESS);
     assert_string_equal(exts.child->stmt, "elem");
     assert_null(exts.child->child);
@@ -3247,6 +3248,163 @@
     st->finished_correctly = true;
 }
 
+static void
+test_deviate_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_deviate *deviates = NULL;
+    struct lysp_deviate_add *d_add;
+    struct lysp_deviate_rpl *d_rpl;
+    struct lysp_deviate_del *d_del;
+
+    /* all valid arguments with min subelems */
+    data = ELEMENT_WRAPPER_START "<deviate value=\"not-supported\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_NOT_SUPPORTED);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"add\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_ADD);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"replace\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_REPLACE);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"delete\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_DELETE);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    /* max subelems and valid arguments */
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"not-supported\">"
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_NOT_SUPPORTED);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"add\">"
+                    "<units name=\"units\"/>"
+                    "<must condition=\"cond\"/>"
+                    "<unique tag=\"utag\"/>"
+                    "<default value=\"def\"/>"
+                    "<config value=\"true\"/>"
+                    "<mandatory value=\"true\"/>"
+                    "<min-elements value=\"5\"/>"
+                    "<max-elements value=\"15\"/>"
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    d_add = (struct lysp_deviate_add *)deviates;
+    assert_int_equal(d_add->mod, LYS_DEV_ADD);
+    assert_null(d_add->next);
+    assert_null(d_add->exts);
+    assert_string_equal(d_add->units, "units");
+    assert_string_equal(d_add->musts->arg, "cond");
+    assert_string_equal(*d_add->uniques, "utag");
+    assert_string_equal(*d_add->dflts, "def");
+    assert_true(d_add->flags & LYS_MAND_TRUE && d_add->flags & LYS_CONFIG_W);
+    assert_int_equal(d_add->min, 5);
+    assert_int_equal(d_add->max, 15);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"replace\">"
+                    "<type name=\"newtype\"/>"
+                    "<units name=\"uni\"/>"
+                    "<default value=\"def\"/>"
+                    "<config value=\"true\"/>"
+                    "<mandatory value=\"true\"/>"
+                    "<min-elements value=\"5\"/>"
+                    "<max-elements value=\"15\"/>"
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    d_rpl = (struct lysp_deviate_rpl *)deviates;
+    assert_int_equal(d_rpl->mod, LYS_DEV_REPLACE);
+    assert_null(d_rpl->next);
+    assert_null(d_rpl->exts);
+    assert_string_equal(d_rpl->type->name, "newtype");
+    assert_string_equal(d_rpl->units, "uni");
+    assert_string_equal(d_rpl->dflt, "def");
+    assert_true(d_rpl->flags & LYS_MAND_TRUE && d_rpl->flags & LYS_CONFIG_W);
+    assert_int_equal(d_rpl->min, 5);
+    assert_int_equal(d_rpl->max, 15);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"delete\">"
+                    "<units name=\"u\"/>"
+                    "<must condition=\"c\"/>"
+                    "<unique tag=\"tag\"/>"
+                    "<default value=\"default\"/>"
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    d_del = (struct lysp_deviate_del *)deviates;
+    assert_int_equal(d_del->mod, LYS_DEV_DELETE);
+    assert_null(d_del->next);
+    assert_null(d_del->exts);
+    assert_string_equal(d_del->units, "u");
+    assert_string_equal(d_del->musts->arg, "c");
+    assert_string_equal(*d_del->uniques, "tag");
+    assert_string_equal(*d_del->dflts, "default");
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    /* invalid arguments */
+    data = ELEMENT_WRAPPER_START "<deviate value=\"\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"\" of \"deviate\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"invalid\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"invalid\" of \"deviate\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"ad\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"ad\" of \"deviate\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"adds\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"adds\" of \"deviate\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"not-supported\">"
+                    "<must condition=\"c\"/>"
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Deviate of this type doesn't allow \"must\" as it's sub-element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
 int
 main(void)
 {
@@ -3316,6 +3474,7 @@
         cmocka_unit_test_setup_teardown(test_inout_elem, setup_element_test, teardown_element_test),
         cmocka_unit_test_setup_teardown(test_action_elem, setup_element_test, teardown_element_test),
         cmocka_unit_test_setup_teardown(test_augment_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_deviate_elem, setup_element_test, teardown_element_test),
     };
 
     return cmocka_run_group_tests(tests, setup_ly_ctx, destroy_ly_ctx);