tests CHANGE enhance yang parser tests
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 5cf8276..e7f4c2c 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -4186,6 +4186,10 @@
LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
+ if (d_rpl->type) {
+ LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+ return LY_EVALID;
+ }
d_rpl->type = calloc(1, sizeof *d_rpl->type);
LY_CHECK_ERR_RET(!d_rpl->type, LOGMEM(ctx->ctx), LY_EMEM);
ret = parse_type(ctx, data, d_rpl->type);
@@ -4331,7 +4335,7 @@
break;
default:
LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
- return LY_EMEM;
+ return LY_EVALID;
}
LY_CHECK_RET(ret);
}
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index fa47925..1020b0a 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -68,6 +68,12 @@
# define logbuf_assert(str)
#endif
+#define TEST_DUP_GENERIC(PREFIX, MEMBER, VALUE1, VALUE2, FUNC, RESULT, LINE, CLEANUP) \
+ str = PREFIX MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
+ assert_int_equal(LY_EVALID, FUNC(&ctx, &str, RESULT)); \
+ logbuf_assert("Duplicate keyword \""MEMBER"\". Line number "LINE"."); \
+ CLEANUP
+
static void
test_helpers(void **state)
{
@@ -696,16 +702,17 @@
assert_non_null(TARGET); \
TEST; \
mod = mod_renew(&ctx, mod, 0);
+#define TEST_DUP(MEMBER, VALUE1, VALUE2, LINE, SUBMODULE) \
+ TEST_DUP_GENERIC(SCHEMA_BEGINNING, MEMBER, VALUE1, VALUE2, \
+ parse_sub_module, mod, LINE, mod = mod_renew(&ctx, mod, SUBMODULE))
/* duplicated namespace, prefix */
- str = SCHEMA_BEGINNING "namespace y;}";
- assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
- logbuf_assert("Duplicate keyword \"namespace\". Line number 1.");
- mod = mod_renew(&ctx, mod, 0);
- str = SCHEMA_BEGINNING "prefix y;}";
- assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
- logbuf_assert("Duplicate keyword \"prefix\". Line number 1.");
- mod = mod_renew(&ctx, mod, 0);
+ TEST_DUP("namespace", "y", "z", "1", 0);
+ TEST_DUP("prefix", "y", "z", "1", 0);
+ TEST_DUP("contact", "a", "b", "1", 0);
+ TEST_DUP("description", "a", "b", "1", 0);
+ TEST_DUP("organization", "a", "b", "1", 0);
+ TEST_DUP("reference", "a", "b", "1", 0);
/* not allowed in module (submodule-specific) */
str = SCHEMA_BEGINNING "belongs-to master {prefix m;}}";
@@ -808,6 +815,12 @@
assert_int_equal(LYEXT_SUBSTMT_SELF, mod->exts[0].insubstmt));
mod = mod_renew(&ctx, mod, 0);
+ /* invalid substatement */
+ str = SCHEMA_BEGINNING "must false;}";
+ assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
+ logbuf_assert("Invalid keyword \"must\" as a child of \"module\". Line number 3.");
+ mod = mod_renew(&ctx, mod, 0);
+
/* submodule */
mod->submodule = 1;
@@ -827,10 +840,7 @@
#define SCHEMA_BEGINNING " subname {belongs-to name;"
/* duplicated namespace, prefix */
- str = SCHEMA_BEGINNING "belongs-to othermodule;}";
- assert_int_equal(LY_EVALID, parse_sub_module(&ctx, &str, mod));
- logbuf_assert("Duplicate keyword \"belongs-to\". Line number 3.");
- mod = mod_renew(&ctx, mod, 1);
+ TEST_DUP("belongs-to", "module1", "module2", "3", 1);
/* not allowed in submodule (module-specific) */
str = SCHEMA_BEGINNING "namespace \"urn:z\";}";
@@ -844,6 +854,7 @@
#undef TEST_GENERIC
#undef TEST_NODE
+#undef TEST_DUP
#undef SCHEMA_BEGINNING
lysp_module_free(mod);
@@ -867,22 +878,208 @@
/* invalid cardinality */
#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
- str = " test {"MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
- assert_int_equal(LY_EVALID, parse_identity(&ctx, &str, &ident)); \
- logbuf_assert("Duplicate keyword \""MEMBER"\". Line number 1."); \
- FREE_ARRAY(ctx.ctx, ident, u, lysp_ident_free); \
- ident = NULL;
+ TEST_DUP_GENERIC(" test {", MEMBER, VALUE1, VALUE2, parse_identity, \
+ &ident, "1", FREE_ARRAY(ctx.ctx, ident, u, lysp_ident_free); ident = NULL)
TEST_DUP("description", "a", "b");
TEST_DUP("reference", "a", "b");
TEST_DUP("status", "current", "obsolete");
- /* full identity */
- str = " test {base \"a\";base b; description text;reference \'another text\';status current; if-feature x;if-feature y;} ...";
+ /* full content */
+ str = " test {base \"a\";base b; description text;reference \'another text\';status current; if-feature x;if-feature y;prefix:ext;} ...";
assert_int_equal(LY_SUCCESS, parse_identity(&ctx, &str, &ident));
assert_non_null(ident);
assert_string_equal(" ...", str);
FREE_ARRAY(ctx.ctx, ident, u, lysp_ident_free);
+ ident = NULL;
+
+ /* invalid substatement */
+ str = " test {organization XXX;}";
+ assert_int_equal(LY_EVALID, parse_identity(&ctx, &str, &ident));
+ logbuf_assert("Invalid keyword \"organization\" as a child of \"identity\". Line number 1.");
+ FREE_ARRAY(ctx.ctx, ident, u, lysp_ident_free);
+ ident = NULL;
+
+#undef TEST_DUP
+
+ ly_ctx_destroy(ctx.ctx, NULL);
+}
+
+static void
+test_feature(void **state)
+{
+ (void) state; /* unused */
+
+ struct ly_parser_ctx ctx;
+ struct lysp_feature *features = NULL;
+ const char *str;
+ unsigned int u;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+ assert_non_null(ctx.ctx);
+ ctx.line = 1;
+ ctx.indent = 0;
+
+ /* invalid cardinality */
+#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+ TEST_DUP_GENERIC(" test {", MEMBER, VALUE1, VALUE2, parse_feature, \
+ &features, "1", FREE_ARRAY(ctx.ctx, features, u, lysp_feature_free); features = NULL)
+
+ TEST_DUP("description", "a", "b");
+ TEST_DUP("reference", "a", "b");
+ TEST_DUP("status", "current", "obsolete");
+
+ /* full content */
+ str = " test {description text;reference \'another text\';status current; if-feature x;if-feature y;prefix:ext;} ...";
+ assert_int_equal(LY_SUCCESS, parse_feature(&ctx, &str, &features));
+ assert_non_null(features);
+ assert_string_equal(" ...", str);
+ FREE_ARRAY(ctx.ctx, features, u, lysp_feature_free);
+ features = NULL;
+
+ /* invalid substatement */
+ str = " test {organization XXX;}";
+ assert_int_equal(LY_EVALID, parse_feature(&ctx, &str, &features));
+ logbuf_assert("Invalid keyword \"organization\" as a child of \"feature\". Line number 1.");
+ FREE_ARRAY(ctx.ctx, features, u, lysp_feature_free);
+ features = NULL;
+
+#undef TEST_DUP
+
+ ly_ctx_destroy(ctx.ctx, NULL);
+}
+
+static void
+test_deviation(void **state)
+{
+ (void) state; /* unused */
+
+ struct ly_parser_ctx ctx;
+ struct lysp_deviation *d = NULL;
+ const char *str;
+ unsigned int u;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+ assert_non_null(ctx.ctx);
+ ctx.line = 1;
+ ctx.indent = 0;
+
+ /* invalid cardinality */
+#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+ TEST_DUP_GENERIC(" test {deviate not-supported;", MEMBER, VALUE1, VALUE2, parse_deviation, \
+ &d, "1", FREE_ARRAY(ctx.ctx, d, u, lysp_deviation_free); d = NULL)
+
+ TEST_DUP("description", "a", "b");
+ TEST_DUP("reference", "a", "b");
+
+ /* full content */
+ str = " test {deviate not-supported;description text;reference \'another text\';prefix:ext;} ...";
+ assert_int_equal(LY_SUCCESS, parse_deviation(&ctx, &str, &d));
+ assert_non_null(d);
+ assert_string_equal(" ...", str);
+ FREE_ARRAY(ctx.ctx, d, u, lysp_deviation_free);
+ d = NULL;
+
+ /* missing mandatory substatement */
+ str = " test {description text;}";
+ assert_int_equal(LY_EVALID, parse_deviation(&ctx, &str, &d));
+ logbuf_assert("Missing mandatory keyword \"deviate\" as a child of \"deviation\". Line number 1.");
+ FREE_ARRAY(ctx.ctx, d, u, lysp_deviation_free);
+ d = NULL;
+
+ /* invalid substatement */
+ str = " test {deviate not-supported; status obsolete;}";
+ assert_int_equal(LY_EVALID, parse_deviation(&ctx, &str, &d));
+ logbuf_assert("Invalid keyword \"status\" as a child of \"deviation\". Line number 1.");
+ FREE_ARRAY(ctx.ctx, d, u, lysp_deviation_free);
+ d = NULL;
+
+#undef TEST_DUP
+
+ ly_ctx_destroy(ctx.ctx, NULL);
+}
+
+static void
+test_deviate(void **state)
+{
+ (void) state; /* unused */
+
+ struct ly_parser_ctx ctx;
+ struct lysp_deviate *d = NULL;
+ const char *str;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+ assert_non_null(ctx.ctx);
+ ctx.line = 1;
+ ctx.indent = 0;
+
+ /* invalid cardinality */
+#define TEST_DUP(TYPE, MEMBER, VALUE1, VALUE2) \
+ TEST_DUP_GENERIC(TYPE" {", MEMBER, VALUE1, VALUE2, parse_deviate, \
+ &d, "1", lysp_deviate_free(ctx.ctx, d); free(d); d = NULL)
+
+ TEST_DUP("add", "config", "true", "false");
+ TEST_DUP("replace", "default", "int8", "uint8");
+ TEST_DUP("add", "mandatory", "true", "false");
+ TEST_DUP("add", "max-elements", "1", "2");
+ TEST_DUP("add", "min-elements", "1", "2");
+ TEST_DUP("replace", "type", "int8", "uint8");
+ TEST_DUP("add", "units", "kilometers", "miles");
+
+ /* full contents */
+ str = " not-supported {prefix:ext;} ...";
+ assert_int_equal(LY_SUCCESS, parse_deviate(&ctx, &str, &d));
+ assert_non_null(d);
+ assert_string_equal(" ...", str);
+ lysp_deviate_free(ctx.ctx, d); free(d); d = NULL;
+ str = " add {units meters; must 1; must 2; unique x; unique y; default a; default b; config true; mandatory true; min-elements 1; max-elements 2; prefix:ext;} ...";
+ assert_int_equal(LY_SUCCESS, parse_deviate(&ctx, &str, &d));
+ assert_non_null(d);
+ assert_string_equal(" ...", str);
+ lysp_deviate_free(ctx.ctx, d); free(d); d = NULL;
+ str = " delete {units meters; must 1; must 2; unique x; unique y; default a; default b; prefix:ext;} ...";
+ assert_int_equal(LY_SUCCESS, parse_deviate(&ctx, &str, &d));
+ assert_non_null(d);
+ assert_string_equal(" ...", str);
+ lysp_deviate_free(ctx.ctx, d); free(d); d = NULL;
+ str = " replace {type string; units meters; default a; config true; mandatory true; min-elements 1; max-elements 2; prefix:ext;} ...";
+ assert_int_equal(LY_SUCCESS, parse_deviate(&ctx, &str, &d));
+ assert_non_null(d);
+ assert_string_equal(" ...", str);
+ lysp_deviate_free(ctx.ctx, d); free(d); d = NULL;
+
+ /* invalid substatements */
+#define TEST_NOT_SUP(DEV, STMT, VALUE) \
+ str = " "DEV" {"STMT" "VALUE";}..."; \
+ assert_int_equal(LY_EVALID, parse_deviate(&ctx, &str, &d)); \
+ logbuf_assert("Deviate \""DEV"\" does not support keyword \""STMT"\". Line number 1."); \
+ lysp_deviate_free(ctx.ctx, d); free(d); d = NULL
+
+ TEST_NOT_SUP("not-supported", "units", "meters");
+ TEST_NOT_SUP("not-supported", "must", "1");
+ TEST_NOT_SUP("not-supported", "unique", "x");
+ TEST_NOT_SUP("not-supported", "default", "a");
+ TEST_NOT_SUP("not-supported", "config", "true");
+ TEST_NOT_SUP("not-supported", "mandatory", "true");
+ TEST_NOT_SUP("not-supported", "min-elements", "1");
+ TEST_NOT_SUP("not-supported", "max-elements", "2");
+ TEST_NOT_SUP("not-supported", "type", "string");
+ TEST_NOT_SUP("add", "type", "string");
+ TEST_NOT_SUP("delete", "config", "true");
+ TEST_NOT_SUP("delete", "mandatory", "true");
+ TEST_NOT_SUP("delete", "min-elements", "1");
+ TEST_NOT_SUP("delete", "max-elements", "2");
+ TEST_NOT_SUP("delete", "type", "string");
+ TEST_NOT_SUP("replace", "must", "1");
+ TEST_NOT_SUP("replace", "unique", "a");
+
+ str = " nonsence; ...";
+ assert_int_equal(LY_EVALID, parse_deviate(&ctx, &str, &d));
+ logbuf_assert("Invalid value \"nonsence\" of \"deviate\". Line number 1.");
+ assert_null(d);
+
+#undef TEST_NOT_SUP
+#undef TEST_DUP
ly_ctx_destroy(ctx.ctx, NULL);
}
@@ -896,6 +1093,9 @@
cmocka_unit_test_setup(test_stmts, logger_setup),
cmocka_unit_test_setup(test_module, logger_setup),
cmocka_unit_test_setup(test_identity, logger_setup),
+ cmocka_unit_test_setup(test_feature, logger_setup),
+ cmocka_unit_test_setup(test_deviation, logger_setup),
+ cmocka_unit_test_setup(test_deviate, logger_setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);