* Support for multiple patterns as described in RFC7950 Section 9.4.7

* Added regex cache to type resolution
* Added compiled regexp parameter as part of internal yang type resolution functions
* All internal `ys_populate_*()` functions (except ys_populate()) have switched parameters: `clicon_handle, yang_stmt *)`
This commit is contained in:
Olof hagsand 2019-05-29 11:39:09 +02:00
parent efd1330550
commit 2fe185d683
21 changed files with 854 additions and 604 deletions

View file

@ -3,6 +3,18 @@
## 3.10.0/4.0.0 (Upcoming) ## 3.10.0/4.0.0 (Upcoming)
### Major New features ### Major New features
* Regexp improvements: Libxml2 XSD, multiple patterns, optimization
* Support for multiple patterns as described in RFC7950 Section 9.4.7
* Libxml2 support for full XSD matching as alternative to Posix translation
* Configure with: `./configure --with-libxml2`
* Set `CLICON_YANG_REGEXP` to libxml2 (default is posix)
* Note you need to configure cligen as well with `--with-libxml2`
* Better compliance with XSD regexps in the default Posix translation regex mode
* Added `\p{L}` and `\p{N}`
* Added escaping of `$`
* Added clixon_util_regexp utility function
* Added extensive regexp test [test/test_pattern.sh] for both posix and libxml2
* Added regex cache to type resolution
* Yang "min-element" and "max-element" feature supported * Yang "min-element" and "max-element" feature supported
* According to RFC 7950 7.7.4 and 7.7.5 * According to RFC 7950 7.7.4 and 7.7.5
* See (tests)[test/test_minmax.sh] * See (tests)[test/test_minmax.sh]
@ -54,6 +66,9 @@
### API changes on existing features (you may need to change your code) ### API changes on existing features (you may need to change your code)
* Added compiled regexp parameter as part of internal yang type resolution functions
* `yang_type_resolve()`, `yang_type_get()`
* All internal `ys_populate_*()` functions (except ys_populate()) have switched parameters: `clicon_handle, yang_stmt *)`
* Added clicon_handle as parameter to all validate functions * Added clicon_handle as parameter to all validate functions
* Just add `clixon_handle h` to all calls. * Just add `clixon_handle h` to all calls.
* Clixon transaction mechanism has changed which may affect your backend plugin callbacks: * Clixon transaction mechanism has changed which may affect your backend plugin callbacks:
@ -141,14 +156,6 @@
### Minor changes ### Minor changes
* Regexp improvements: Added libxml2 XSD regexp mode as alternative to posix translation
* Configure with: `./configure --with-libxml2`
* Set `CLICON_YANG_REGEXP` to libxml2 (default is posix)
* Better compliance with XSD regexps (when transforming to Posix regexps)
* Added `\p{L}` and `\p{N}`
* Added escaping of `$`
* Added clixon_util_regexp utility function
* Added regexp test [test/test_pattern.sh] for both posix and libxml2
* Yang state get improvements * Yang state get improvements
* Integrated state and config into same tree on retrieval, not separate trees * Integrated state and config into same tree on retrieval, not separate trees
* Added cli functions `cli_show_config_state()` and `cli_show_auto_state()` for showing combined config and state info. * Added cli functions `cli_show_config_state()` and `cli_show_auto_state()` for showing combined config and state info.

View file

@ -477,7 +477,7 @@ from_client_edit_config(clicon_handle h,
/* Cant do this earlier since we dont have a yang spec to /* Cant do this earlier since we dont have a yang spec to
* the upper part of the tree, until we get the "config" tree. * the upper part of the tree, until we get the "config" tree.
*/ */
if (xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0) if (xml_apply0(xc, CX_ELMNT, xml_sort, h) < 0)
goto done; goto done;
if ((ret = xmldb_put(h, target, operation, xc, username, cbret)) < 0){ if ((ret = xmldb_put(h, target, operation, xc, username, cbret)) < 0){
clicon_debug(1, "%s ERROR PUT", __FUNCTION__); clicon_debug(1, "%s ERROR PUT", __FUNCTION__);

View file

@ -206,7 +206,7 @@ startup_common(clicon_handle h,
/* After upgrading, XML tree needs to be sorted and yang spec populated */ /* After upgrading, XML tree needs to be sorted and yang spec populated */
if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0) if (xml_apply0(xt, CX_ELMNT, xml_sort, h) < 0)
goto done; goto done;
/* Handcraft transition with with only add tree */ /* Handcraft transition with with only add tree */
td->td_target = xt; td->td_target = xt;

View file

@ -272,6 +272,42 @@ yang2cli_var_range(yang_stmt *ys,
return retval; return retval;
} }
/*! Generate CLI code for Yang variable pattern statement
* @param[in] h Clixon handle
* @param[in] patterns Cvec of regexp patterns
* @param[out] cb Buffer where cligen code is written
* @see cv_validate_pattern for netconf validate code
*/
static int
yang2cli_var_pattern(clicon_handle h,
cvec *patterns,
cbuf *cb)
{
int retval = -1;
char *mode;
cg_var *cvp;
char *pattern;
mode = clicon_yang_regexp(h);
cvp = NULL; /* Loop over compiled regexps */
while ((cvp = cvec_each(patterns, cvp)) != NULL){
pattern = cv_string_get(cvp);
if (strcmp(mode, "posix") == 0){
char *posix = NULL;
if (regexp_xsd2posix(pattern, &posix) < 0)
goto done;
cprintf(cb, " regexp:\"%s\"", posix);
if (posix)
free(posix);
}
else
cprintf(cb, " regexp:\"%s\"", pattern);
}
retval = 0;
done:
return retval;
}
/* Forward */ /* Forward */
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, static int yang2cli_stmt(clicon_handle h, yang_stmt *ys,
enum genmodel_type gt, int level, cbuf *cb); enum genmodel_type gt, int level, cbuf *cb);
@ -289,7 +325,7 @@ static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
* @param[in] cvtype * @param[in] cvtype
* @param[in] options Flags field of optional values, see YANG_OPTIONS_* * @param[in] options Flags field of optional values, see YANG_OPTIONS_*
* @param[in] cvv Cvec with array of range_min/range_max cv:s * @param[in] cvv Cvec with array of range_min/range_max cv:s
* @param[in] pattern String of POSIX regexp pattern * @param[in] patterns Cvec of regexp patterns
* @param[in] fraction for decimal64, how many digits after period * @param[in] fraction for decimal64, how many digits after period
* @param[out] cb Buffer where cligen code is written * @param[out] cb Buffer where cligen code is written
* @see yang_type_resolve for options and other arguments * @see yang_type_resolve for options and other arguments
@ -302,7 +338,7 @@ yang2cli_var_sub(clicon_handle h,
enum cv_type cvtype, enum cv_type cvtype,
int options, int options,
cvec *cvv, cvec *cvv,
char *pattern, cvec *patterns,
uint8_t fraction_digits, uint8_t fraction_digits,
cbuf *cb cbuf *cb
) )
@ -358,19 +394,9 @@ yang2cli_var_sub(clicon_handle h,
if (yang2cli_var_range(ys, options, cvv, cb) < 0) if (yang2cli_var_range(ys, options, cvv, cb) < 0)
goto done; goto done;
} }
if (options & YANG_OPTIONS_PATTERN){ if (patterns && cvec_len(patterns)){
char *mode; if (yang2cli_var_pattern(h, patterns, cb) < 0)
mode = clicon_yang_regexp(h); goto done;
if (strcmp(mode, "posix") == 0){
char *posix = NULL;
if (regexp_xsd2posix(pattern, &posix) < 0)
goto done;
cprintf(cb, " regexp:\"%s\"", posix);
if (posix)
free(posix);
}
else
cprintf(cb, " regexp:\"%s\"", pattern);
} }
cprintf(cb, ">"); cprintf(cb, ">");
if (helptext) if (helptext)
@ -402,16 +428,20 @@ yang2cli_var_union_one(clicon_handle h,
int retval = -1; int retval = -1;
int options = 0; int options = 0;
cvec *cvv = NULL; cvec *cvv = NULL;
char *pattern = NULL; cvec *patterns = NULL;
uint8_t fraction_digits = 0; uint8_t fraction_digits = 0;
enum cv_type cvtype; enum cv_type cvtype;
yang_stmt *ytype; /* resolved type */ yang_stmt *ytype; /* resolved type */
char *restype; char *restype;
if ((patterns = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
/* Resolve the sub-union type to a resolved type */ /* Resolve the sub-union type to a resolved type */
if (yang_type_resolve(ys, ys, ytsub, /* in */ if (yang_type_resolve(ys, ys, ytsub, /* in */
&ytype, &options, /* resolved type */ &ytype, &options, /* resolved type */
&cvv, &pattern, &fraction_digits) < 0) &cvv, patterns, NULL, &fraction_digits) < 0)
goto done; goto done;
restype = ytype?yang_argument_get(ytype):NULL; restype = ytype?yang_argument_get(ytype):NULL;
@ -423,11 +453,13 @@ yang2cli_var_union_one(clicon_handle h,
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
goto done; goto done;
if ((retval = yang2cli_var_sub(h, ys, ytype, helptext, cvtype, if ((retval = yang2cli_var_sub(h, ys, ytype, helptext, cvtype,
options, cvv, pattern, fraction_digits, cb)) < 0) options, cvv, patterns, fraction_digits, cb)) < 0)
goto done; goto done;
} }
retval = 0; retval = 0;
done: done:
if (patterns)
cvec_free(patterns);
return retval; return retval;
} }
@ -494,15 +526,19 @@ yang2cli_var(clicon_handle h,
yang_stmt *yrestype; /* resolved type */ yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */ char *restype; /* resolved type */
cvec *cvv = NULL; cvec *cvv = NULL;
char *pattern = NULL; cvec *patterns = NULL;
uint8_t fraction_digits = 0; uint8_t fraction_digits = 0;
enum cv_type cvtype; enum cv_type cvtype;
int options = 0; int options = 0;
int completionp; int completionp;
char *type; char *type;
if ((patterns = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (yang_type_get(ys, &origtype, &yrestype, if (yang_type_get(ys, &origtype, &yrestype,
&options, &cvv, &pattern, &fraction_digits) < 0) &options, &cvv, patterns, NULL, &fraction_digits) < 0)
goto done; goto done;
restype = yrestype?yang_argument_get(yrestype):NULL; restype = yrestype?yang_argument_get(yrestype):NULL;
@ -539,7 +575,7 @@ yang2cli_var(clicon_handle h,
if (completionp) if (completionp)
cprintf(cb, "("); cprintf(cb, "(");
if ((retval = yang2cli_var_sub(h, ys, yrestype, helptext, cvtype, if ((retval = yang2cli_var_sub(h, ys, yrestype, helptext, cvtype,
options, cvv, pattern, fraction_digits, cb)) < 0) options, cvv, patterns, fraction_digits, cb)) < 0)
goto done; goto done;
if (completionp){ if (completionp){
if (cli_expand_var_generate(h, ys, cvtype, if (cli_expand_var_generate(h, ys, cvtype,
@ -552,6 +588,8 @@ yang2cli_var(clicon_handle h,
} }
retval = 0; retval = 0;
done: done:
if (patterns)
cvec_free(patterns);
return retval; return retval;
} }

View file

@ -153,8 +153,6 @@ char *yang_argument_get(yang_stmt *ys);
cg_var *yang_cv_get(yang_stmt *ys); cg_var *yang_cv_get(yang_stmt *ys);
cvec *yang_cvec_get(yang_stmt *ys); cvec *yang_cvec_get(yang_stmt *ys);
int yang_cvec_set(yang_stmt *ys, cvec *cvv); int yang_cvec_set(yang_stmt *ys, cvec *cvv);
void *yang_regex_cache_get(yang_stmt *ys);
int yang_regex_cache_set(yang_stmt *ys, void *regex);
/* Other functions */ /* Other functions */
yang_stmt *yspec_new(void); yang_stmt *yspec_new(void);

View file

@ -43,8 +43,7 @@
*/ */
#define YANG_OPTIONS_LENGTH 0x01 #define YANG_OPTIONS_LENGTH 0x01
#define YANG_OPTIONS_RANGE 0x02 #define YANG_OPTIONS_RANGE 0x02
#define YANG_OPTIONS_PATTERN 0x04 #define YANG_OPTIONS_FRACTION_DIGITS 0x04
#define YANG_OPTIONS_FRACTION_DIGITS 0x08
/* /*
* Types * Types
@ -57,10 +56,11 @@ typedef struct yang_type_cache yang_type_cache;
*/ */
int yang_type_cache_set(yang_type_cache **ycache, int yang_type_cache_set(yang_type_cache **ycache,
yang_stmt *resolved, int options, yang_stmt *resolved, int options,
cvec *cvv, char *pattern, uint8_t fraction); cvec *cvv, cvec *patterns, cvec *regexps,
uint8_t fraction);
int yang_type_cache_get(yang_type_cache *ycache, yang_stmt **resolved, int yang_type_cache_get(yang_type_cache *ycache, yang_stmt **resolved,
int *options, cvec **cvv, char **pattern, int *options, cvec **cvv, cvec *patterns,
uint8_t *fraction); cvec *regexps, uint8_t *fraction);
int yang_type_cache_cp(yang_type_cache **ycnew, yang_type_cache *ycold); int yang_type_cache_cp(yang_type_cache **ycnew, yang_type_cache *ycold);
int yang_type_cache_free(yang_type_cache *ycache); int yang_type_cache_free(yang_type_cache *ycache);
int ys_resolve_type(yang_stmt *ys, void *arg); int ys_resolve_type(yang_stmt *ys, void *arg);
@ -70,11 +70,14 @@ yang_stmt *yang_find_identity(yang_stmt *ys, char *identity);
int ys_cv_validate(clicon_handle h, cg_var *cv, yang_stmt *ys, char **reason); int ys_cv_validate(clicon_handle h, cg_var *cv, yang_stmt *ys, char **reason);
int clicon_type2cv(char *type, char *rtype, yang_stmt *ys, enum cv_type *cvtype); int clicon_type2cv(char *type, char *rtype, yang_stmt *ys, enum cv_type *cvtype);
int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype, int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype,
int *options, cvec **cvv, char **pattern, int *options, cvec **cvv,
cvec *patterns, cvec *regexps,
uint8_t *fraction_digits); uint8_t *fraction_digits);
int yang_type_resolve(yang_stmt *yorig, yang_stmt *ys, yang_stmt *ytype, int yang_type_resolve(yang_stmt *yorig, yang_stmt *ys,
yang_stmt *ytype,
yang_stmt **restype, int *options, yang_stmt **restype, int *options,
cvec **cvv, char **pattern, uint8_t *fraction); cvec **cvv, cvec *patterns, cvec *regexps,
uint8_t *fraction);
#endif /* _CLIXON_YANG_TYPE_H_ */ #endif /* _CLIXON_YANG_TYPE_H_ */

View file

@ -437,7 +437,7 @@ xmldb_get_nocache(clicon_handle h,
goto done; goto done;
/* Add default values (if not set) */ /* Add default values (if not set) */
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0) if (xml_apply(xt, CX_ELMNT, xml_default, h) < 0)
goto done; goto done;
#if 0 /* debug */ #if 0 /* debug */
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0) if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
@ -542,7 +542,7 @@ xmldb_get_cache(clicon_handle h,
goto done; goto done;
/* x1t is wrong here should be <config><system>.. but is <system>.. */ /* x1t is wrong here should be <config><system>.. but is <system>.. */
/* XXX where should we apply default values once? */ /* XXX where should we apply default values once? */
if (xml_apply(x1t, CX_ELMNT, xml_default, NULL) < 0) if (xml_apply(x1t, CX_ELMNT, xml_default, h) < 0)
goto done; goto done;
/* Copy the matching parts of the (relevant) XML tree. /* Copy the matching parts of the (relevant) XML tree.
@ -622,7 +622,7 @@ xmldb_get_zerocopy(clicon_handle h,
xml_apply_ancestor(x0, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE); xml_apply_ancestor(x0, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
} }
/* Apply default values (removed in clear function) */ /* Apply default values (removed in clear function) */
if (xml_apply(x0t, CX_ELMNT, xml_default, NULL) < 0) if (xml_apply(x0t, CX_ELMNT, xml_default, h) < 0)
goto done; goto done;
if (debug>1) if (debug>1)
clicon_xml2file(stderr, x0t, 0, 1); clicon_xml2file(stderr, x0t, 0, 1);

View file

@ -398,7 +398,7 @@ text_modify(clicon_handle h,
} /* else Y_CONTAINER */ } /* else Y_CONTAINER */
#ifndef USE_XML_INSERT #ifndef USE_XML_INSERT
if (changed) if (changed)
xml_sort(x0p, NULL); xml_sort(x0p, h);
#endif #endif
retval = 1; retval = 1;
done: done:

View file

@ -181,7 +181,7 @@ parse_configfile(clicon_handle h,
goto done; goto done;
if (xml_apply0(xc, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply0(xc, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if (xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0) if (xml_apply0(xc, CX_ELMNT, xml_sort, h) < 0)
goto done; goto done;
} }
else else
@ -192,7 +192,7 @@ parse_configfile(clicon_handle h,
goto done; goto done;
} }
} }
if (xml_apply0(xc, CX_ELMNT, xml_default, yspec) < 0) if (xml_apply0(xc, CX_ELMNT, xml_default, h) < 0)
goto done; goto done;
if ((cbret = cbuf_new()) == NULL){ if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");

View file

@ -2394,51 +2394,3 @@ clicon_log_xml(int level,
return retval; return retval;
} }
/*
* Turn this on to get a xml parse and pretty print test program
* Usage: xpath
* read xml from input
* Example compile:
gcc -g -o xml -I. -I../clixon ./clixon_xml.c -lclixon -lcligen
* Example run:
echo "<a><b/></a>" | xml
*/
#if 1 /* Test program */
static int
usage(char *argv0)
{
fprintf(stderr, "usage:%s.\n\tInput on stdin\n", argv0);
exit(0);
}
int
main(int argc, char **argv)
{
cxobj *xt = NULL;
cxobj *xc;
cbuf *cb = cbuf_new();
if (argc != 1){
usage(argv[0]);
return 0;
}
if (xml_parse_file(0, "</config>", NULL, &xt) < 0){
fprintf(stderr, "xml parse error %s\n", clicon_err_reason);
return -1;
}
xc = NULL;
while ((xc = xml_child_each(xt, xc, -1)) != NULL) {
xmltree2cbuf(cb, xc, 0); /* dump data structures */
//clicon_xml2cbuf(cb, xc, 0, 1); /* print xml */
}
fprintf(stdout, "%s", cbuf_get(cb));
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return 0;
}
#endif /* Test program */

View file

@ -3004,7 +3004,7 @@ yang_enum_int_value(cxobj *node,
if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL) if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL)
goto done; goto done;
if (yang_type_resolve(ys, ys, ytype, &yrestype, if (yang_type_resolve(ys, ys, ytype, &yrestype,
NULL, NULL, NULL, NULL) < 0) NULL, NULL, NULL, NULL, NULL) < 0)
goto done; goto done;
if (yrestype==NULL || strcmp(yrestype->ys_argument, "enumeration")) if (yrestype==NULL || strcmp(yrestype->ys_argument, "enumeration"))
goto done; goto done;

View file

@ -95,7 +95,7 @@ xml_cv_cache(cxobj *x,
goto ok; goto ok;
if ((y = xml_spec(x)) == NULL) if ((y = xml_spec(x)) == NULL)
goto ok; goto ok;
if (yang_type_get(y, NULL, &yrestype, &options, NULL, NULL, &fraction) < 0) if (yang_type_get(y, NULL, &yrestype, &options, NULL, NULL, NULL, &fraction) < 0)
goto done; goto done;
yang2cv_type(yang_argument_get(yrestype), &cvtype); yang2cv_type(yang_argument_get(yrestype), &cvtype);
if (cvtype==CGV_ERR){ if (cvtype==CGV_ERR){

View file

@ -239,30 +239,6 @@ yang_cvec_set(yang_stmt *ys,
return 0; return 0;
} }
/*! Get regular expression cache - the compiled regex
* @param[in] ys Yang statement node
* @retval re Compiled regex
* @see regcomp
*/
void*
yang_regex_cache_get(yang_stmt *ys)
{
return ys->ys_regex_cache;
}
/*! Set regular expression cache - the compiled regex
* @param[in] ys Yang statement node
* @param[in] re Compiled regex
* @see regcomp
*/
int
yang_regex_cache_set(yang_stmt *ys,
void *regex)
{
ys->ys_regex_cache = regex;
return 0;
}
/* End access functions */ /* End access functions */
/*! Create new yang specification /*! Create new yang specification
@ -307,17 +283,6 @@ ys_new(enum rfc_6020 keyw)
return ys; return ys;
} }
static int
yang_regex_cache_free(yang_stmt *ys)
{
if (ys->ys_regex_cache){
regfree(ys->ys_regex_cache);
free(ys->ys_regex_cache);
}
return 0;
}
/*! Free a single yang statement */ /*! Free a single yang statement */
static int static int
ys_free1(yang_stmt *ys) ys_free1(yang_stmt *ys)
@ -332,7 +297,6 @@ ys_free1(yang_stmt *ys)
cvec_free(ys->ys_cvec); cvec_free(ys->ys_cvec);
if (ys->ys_typecache) if (ys->ys_typecache)
yang_type_cache_free(ys->ys_typecache); yang_type_cache_free(ys->ys_typecache);
yang_regex_cache_free(ys);
free(ys); free(ys);
return 0; return 0;
} }
@ -1344,8 +1308,8 @@ yang_print_cbuf(cbuf *cb,
* @retval -1 Error with clicon_err called * @retval -1 Error with clicon_err called
*/ */
static int static int
ys_populate_leaf(yang_stmt *ys, ys_populate_leaf(clicon_handle h,
void *arg) yang_stmt *ys)
{ {
int retval = -1; int retval = -1;
cg_var *cv = NULL; cg_var *cv = NULL;
@ -1363,7 +1327,7 @@ ys_populate_leaf(yang_stmt *ys,
yparent = ys->ys_parent; /* Find parent: list/container */ yparent = ys->ys_parent; /* Find parent: list/container */
/* 1. Find type specification and set cv type accordingly */ /* 1. Find type specification and set cv type accordingly */
if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, &fraction_digits) if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, NULL, &fraction_digits)
< 0) < 0)
goto done; goto done;
restype = yrestype?yrestype->ys_argument:NULL; restype = yrestype?yrestype->ys_argument:NULL;
@ -1416,8 +1380,8 @@ ys_populate_leaf(yang_stmt *ys,
} }
static int static int
ys_populate_list(yang_stmt *ys, ys_populate_list(clicon_handle h,
void *arg) yang_stmt *ys)
{ {
yang_stmt *ykey; yang_stmt *ykey;
@ -1523,8 +1487,8 @@ range_parse(yang_stmt *ys,
* ascending order * ascending order
*/ */
static int static int
ys_populate_range(yang_stmt *ys, ys_populate_range(clicon_handle h,
void *arg) yang_stmt *ys)
{ {
int retval = -1; int retval = -1;
yang_stmt *yparent; /* type */ yang_stmt *yparent; /* type */
@ -1541,7 +1505,7 @@ ys_populate_range(yang_stmt *ys,
goto done; goto done;
} }
if (yang_type_resolve(ys, ys, (yang_stmt*)yparent, &yrestype, if (yang_type_resolve(ys, ys, (yang_stmt*)yparent, &yrestype,
&options, NULL, NULL, &fraction_digits) < 0) &options, NULL, NULL, NULL, &fraction_digits) < 0)
goto done; goto done;
restype = yrestype?yrestype->ys_argument:NULL; restype = yrestype?yrestype->ys_argument:NULL;
origtype = yarg_id((yang_stmt*)yparent); origtype = yarg_id((yang_stmt*)yparent);
@ -1572,8 +1536,8 @@ ys_populate_range(yang_stmt *ys,
* be disjoint and MUST be in ascending order. * be disjoint and MUST be in ascending order.
*/ */
static int static int
ys_populate_length(yang_stmt *ys, ys_populate_length(clicon_handle h,
void *arg) yang_stmt *ys)
{ {
int retval = -1; int retval = -1;
yang_stmt *yparent; /* type */ yang_stmt *yparent; /* type */
@ -1598,8 +1562,9 @@ ys_populate_length(yang_stmt *ys,
* @ * @
*/ */
static int static int
ys_populate_type(yang_stmt *ys, ys_populate_type(clicon_handle h,
void *arg) yang_stmt *ys)
{ {
int retval = -1; int retval = -1;
yang_stmt *ybase; yang_stmt *ybase;
@ -1636,8 +1601,9 @@ ys_populate_type(yang_stmt *ys,
* @see validate_identityref which in runtime validates actual values * @see validate_identityref which in runtime validates actual values
*/ */
static int static int
ys_populate_identity(yang_stmt *ys, ys_populate_identity(clicon_handle h,
char *idref) yang_stmt *ys,
char *idref)
{ {
int retval = -1; int retval = -1;
yang_stmt *yc = NULL; yang_stmt *yc = NULL;
@ -1695,7 +1661,7 @@ ys_populate_identity(yang_stmt *ys,
cv = NULL; cv = NULL;
} }
/* Transitive to the root */ /* Transitive to the root */
if (ys_populate_identity(ybaseid, idref) < 0) if (ys_populate_identity(h, ybaseid, idref) < 0)
goto done; goto done;
} }
retval = 0; retval = 0;
@ -1800,7 +1766,8 @@ ys_populate_feature(clicon_handle h,
/*! Populate the unique statement with a cvec /*! Populate the unique statement with a cvec
*/ */
static int static int
ys_populate_unique(yang_stmt *ys) ys_populate_unique(clicon_handle h,
yang_stmt *ys)
{ {
if (ys->ys_cvec) if (ys->ys_cvec)
cvec_free(ys->ys_cvec); cvec_free(ys->ys_cvec);
@ -1812,7 +1779,8 @@ ys_populate_unique(yang_stmt *ys)
/*! Populate unknown node with extension /*! Populate unknown node with extension
*/ */
static int static int
ys_populate_unknown(yang_stmt *ys) ys_populate_unknown(clicon_handle h,
yang_stmt *ys)
{ {
int retval = -1; int retval = -1;
int cvret; int cvret;
@ -1861,28 +1829,28 @@ ys_populate_unknown(yang_stmt *ys)
* After this pass, cv:s are set for LEAFs and LEAF-LISTs * After this pass, cv:s are set for LEAFs and LEAF-LISTs
*/ */
int int
ys_populate(yang_stmt *ys, ys_populate(yang_stmt *ys,
void *arg) void *arg)
{ {
int retval = -1; int retval = -1;
// clicon_handle h = (clicon_handle)arg; clicon_handle h = (clicon_handle)arg;
switch(ys->ys_keyword){ switch(ys->ys_keyword){
case Y_LEAF: case Y_LEAF:
case Y_LEAF_LIST: case Y_LEAF_LIST:
if (ys_populate_leaf(ys, NULL) < 0) if (ys_populate_leaf(h, ys) < 0)
goto done; goto done;
break; break;
case Y_LIST: case Y_LIST:
if (ys_populate_list(ys, NULL) < 0) if (ys_populate_list(h, ys) < 0)
goto done; goto done;
break; break;
case Y_RANGE: case Y_RANGE:
if (ys_populate_range(ys, NULL) < 0) if (ys_populate_range(h, ys) < 0)
goto done; goto done;
break; break;
case Y_LENGTH: case Y_LENGTH:
if (ys_populate_length(ys, NULL) < 0) if (ys_populate_length(h, ys) < 0)
goto done; goto done;
break; break;
case Y_MANDATORY: /* call yang_mandatory() to check if set */ case Y_MANDATORY: /* call yang_mandatory() to check if set */
@ -1891,19 +1859,19 @@ ys_populate(yang_stmt *ys,
goto done; goto done;
break; break;
case Y_TYPE: case Y_TYPE:
if (ys_populate_type(ys, NULL) < 0) if (ys_populate_type(h, ys) < 0)
goto done; goto done;
break; break;
case Y_IDENTITY: case Y_IDENTITY:
if (ys_populate_identity(ys, NULL) < 0) if (ys_populate_identity(h, ys, NULL) < 0)
goto done; goto done;
break; break;
case Y_UNIQUE: case Y_UNIQUE:
if (ys_populate_unique(ys) < 0) if (ys_populate_unique(h, ys) < 0)
goto done; goto done;
break; break;
case Y_UNKNOWN: case Y_UNKNOWN:
if (ys_populate_unknown(ys) < 0) if (ys_populate_unknown(h, ys) < 0)
goto done; goto done;
break; break;
default: default:
@ -2631,7 +2599,7 @@ yang_parse_post(clicon_handle h,
* Must be done using static binding. * Must be done using static binding.
*/ */
for (i=modnr; i<yspec->ys_len; i++) for (i=modnr; i<yspec->ys_len; i++)
if (yang_apply(yspec->ys_stmt[i], Y_TYPE, ys_resolve_type, NULL) < 0) if (yang_apply(yspec->ys_stmt[i], Y_TYPE, ys_resolve_type, h) < 0)
goto done; goto done;
/* Up to here resolving is made in the context they are defined, rather /* Up to here resolving is made in the context they are defined, rather

View file

@ -58,7 +58,8 @@ struct yang_type_cache{
cvec *yc_cvv; /* Range and length restriction. (if YANG_OPTION_ cvec *yc_cvv; /* Range and length restriction. (if YANG_OPTION_
LENGTH|RANGE. Can be a vector if multiple LENGTH|RANGE. Can be a vector if multiple
ranges*/ ranges*/
char *yc_pattern; /* regex (posix) (if YANG_OPTIONS_PATTERN) */ cvec *yc_patterns; /* list of regexp, if cvec_len() > 0 */
cvec *yc_regexps; /* list of _compiled_ regexp, if cvec_len() > 0 */
uint8_t yc_fraction; /* Fraction digits for decimal64 (if uint8_t yc_fraction; /* Fraction digits for decimal64 (if
YANG_OPTIONS_FRACTION_DIGITS */ YANG_OPTIONS_FRACTION_DIGITS */
yang_stmt *yc_resolved; /* Resolved type object, can be NULL - note direct ptr */ yang_stmt *yc_resolved; /* Resolved type object, can be NULL - note direct ptr */
@ -95,7 +96,6 @@ struct yang_stmt{
Y_TYPE & identity: store all derived types Y_TYPE & identity: store all derived types
*/ */
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */ yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
void *ys_regex_cache; /* regex cache */
int _ys_vector_i; /* internal use: yn_each */ int _ys_vector_i; /* internal use: yn_each */
}; };

View file

@ -170,6 +170,7 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<KEYWORD>key { BEGIN(STRING); return K_KEY; } <KEYWORD>key { BEGIN(STRING); return K_KEY; }
<KEYWORD>length { BEGIN(STRING); return K_LENGTH; } <KEYWORD>length { BEGIN(STRING); return K_LENGTH; }
<KEYWORD>max-elements { BEGIN(STRING); return K_MAX_ELEMENTS; } <KEYWORD>max-elements { BEGIN(STRING); return K_MAX_ELEMENTS; }
<KEYWORD>modifier { BEGIN(STRING); return K_MODIFIER; }
<KEYWORD>must { BEGIN(STRING); return K_MUST; } <KEYWORD>must { BEGIN(STRING); return K_MUST; }
<KEYWORD>namespace { BEGIN(STRING); return K_NAMESPACE; } <KEYWORD>namespace { BEGIN(STRING); return K_NAMESPACE; }
<KEYWORD>ordered-by { BEGIN(STRING); return K_ORDERED_BY; } <KEYWORD>ordered-by { BEGIN(STRING); return K_ORDERED_BY; }

View file

@ -863,7 +863,7 @@ pattern_substmt : modifier_stmt { clicon_debug(2,"pattern-substmt -> modifier
; ;
modifier_stmt : K_MODIFIER string stmtend modifier_stmt : K_MODIFIER string stmtend
{ if (ysp_add(_yy, Y_DEFAULT, $2, NULL)== NULL) _YYERROR("modifier_stmt"); { if (ysp_add(_yy, Y_MODIFIER, $2, NULL)== NULL) _YYERROR("modifier_stmt");
clicon_debug(2,"modifier-stmt -> MODIFIER string"); } clicon_debug(2,"modifier-stmt -> MODIFIER string"); }
; ;

View file

@ -32,6 +32,20 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
* Yang type related functions * Yang type related functions
* Part of this is type resolving which is pretty complex
*
* (called at parse / set cache)
* ys_resolve_type --+ ys_populate_range, yang_enum_int_value(NULL)
* \ | cml
* v v v
* yang_type_get --> yang_type_resolve --> resolve_restrictions
* (leaf(list) front) (recursive core fn) (regexps, length, ranges, ...)
* ^ ^ ^ ^
* | | | |
* | yang2cli_var | yang2cli_var_union_one
* ys_cv_validate ys_cv_validate_union_one
* |
* ys_populate_leaf, xml_cv_cache (NULL)
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -145,7 +159,8 @@ yang_type_cache_set(yang_type_cache **ycache0,
yang_stmt *resolved, yang_stmt *resolved,
int options, int options,
cvec *cvv, cvec *cvv,
char *pattern, cvec *patterns,
cvec *regexps,
uint8_t fraction) uint8_t fraction)
{ {
int retval = -1; int retval = -1;
@ -166,8 +181,12 @@ yang_type_cache_set(yang_type_cache **ycache0,
goto done; goto done;
} }
} }
if (pattern && (ycache->yc_pattern = strdup(pattern)) == NULL){ if (patterns && (ycache->yc_patterns = cvec_dup(patterns)) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "cvec_dup");
goto done;
}
if (regexps && (ycache->yc_regexps = cvec_dup(regexps)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_dup");
goto done; goto done;
} }
ycache->yc_fraction = fraction; ycache->yc_fraction = fraction;
@ -176,26 +195,42 @@ yang_type_cache_set(yang_type_cache **ycache0,
return retval; return retval;
} }
/*! Get individual fields (direct/destructively) from yang type cache. */ /*! Get individual fields (direct/destructively) from yang type cache.
* @param[out] patterns Initialized cvec of regexp patterns strings
*/
int int
yang_type_cache_get(yang_type_cache *ycache, yang_type_cache_get(yang_type_cache *ycache,
yang_stmt **resolved, yang_stmt **resolved,
int *options, int *options,
cvec **cvv, cvec **cvv,
char **pattern, cvec *patterns,
cvec *regexps,
uint8_t *fraction) uint8_t *fraction)
{ {
int retval = -1;
cg_var *cv = NULL;
if (resolved) if (resolved)
*resolved = ycache->yc_resolved; *resolved = ycache->yc_resolved;
if (options) if (options)
*options = ycache->yc_options; *options = ycache->yc_options;
if (cvv) if (cvv)
*cvv = ycache->yc_cvv; *cvv = ycache->yc_cvv;
if (pattern) if (patterns){
*pattern = ycache->yc_pattern; cv = NULL;
while ((cv = cvec_each(ycache->yc_patterns, cv)) != NULL)
cvec_append_var(patterns, cv);
}
if (regexps){
cv = NULL;
while ((cv = cvec_each(ycache->yc_regexps, cv)) != NULL)
cvec_append_var(regexps, cv);
}
if (fraction) if (fraction)
*fraction = ycache->yc_fraction; *fraction = ycache->yc_fraction;
return 0; retval = 0;
// done:
return retval;
} }
int int
@ -205,15 +240,28 @@ yang_type_cache_cp(yang_type_cache **ycnew,
int retval = -1; int retval = -1;
int options; int options;
cvec *cvv; cvec *cvv;
char *pattern; cvec *patterns = NULL;
cvec *regexps = NULL;
uint8_t fraction; uint8_t fraction;
yang_stmt *resolved; yang_stmt *resolved;
yang_type_cache_get(ycold, &resolved, &options, &cvv, &pattern, &fraction); if ((patterns = cvec_new(0)) == NULL){
if (yang_type_cache_set(ycnew, resolved, options, cvv, pattern, fraction) < 0) clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if ((regexps = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
yang_type_cache_get(ycold, &resolved, &options, &cvv, patterns, regexps, &fraction);
if (yang_type_cache_set(ycnew, resolved, options, cvv, patterns, regexps, fraction) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
if (patterns)
cvec_free(patterns);
if (regexps)
cvec_free(regexps);
return retval; return retval;
} }
@ -222,12 +270,59 @@ yang_type_cache_free(yang_type_cache *ycache)
{ {
if (ycache->yc_cvv) if (ycache->yc_cvv)
cvec_free(ycache->yc_cvv); cvec_free(ycache->yc_cvv);
if (ycache->yc_pattern) if (ycache->yc_patterns)
free(ycache->yc_pattern); cvec_free(ycache->yc_patterns);
if (ycache->yc_regexps)
cvec_free(ycache->yc_regexps);
free(ycache); free(ycache);
return 0; return 0;
} }
/* Compile yang patterns in string form to regex compiled void* form
* and re-store into "patterns" cvec.
* This is done here instead of deep in resolve code (resolve_restrictions)
* since it id dependent on clicon_handle.
* The downside is that all accesses to "patterns" must pass via the cache.
* If calls to yang_type_resolve is made without the cache is set, will be
* wrong.
*/
static int
compile_pattern2regexp(clicon_handle h,
cvec *patterns,
cvec *regexps)
{
int retval = -1;
cg_var *pcv; /* pattern cv */
cg_var *rcv; /* regexp cv */
void *re;
int ret;
char *pattern;
pcv = NULL;
while ((pcv = cvec_each(patterns, pcv)) != NULL){
if (cv_type_get(pcv) == CGV_VOID)
continue; /* already compiled */
pattern = cv_string_get(pcv);
/* Compile yang pattern. handle necessary to select regex engine */
if ((ret = regex_compile(h, pattern, &re)) < 0)
goto done;
if (ret == 0){
clicon_err(OE_YANG, errno, "regexp compile fail: \"%s\"",
pattern);
goto done;
break;
}
if ((rcv = cvec_add(regexps, CGV_VOID)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_add");
goto done;
}
cv_void_set(rcv, re);
}
retval = 1;
done:
return retval;
}
/*! Resolve types: populate type caches /*! Resolve types: populate type caches
* @param[in] ys This is a type statement * @param[in] ys This is a type statement
* @param[in] arg Not used * @param[in] arg Not used
@ -235,31 +330,58 @@ yang_type_cache_free(yang_type_cache *ycache)
* @note unions not cached * @note unions not cached
*/ */
int int
ys_resolve_type(yang_stmt *ys, ys_resolve_type(yang_stmt *ys,
void *arg) void *arg)
{ {
clicon_handle h = (clicon_handle)arg;
int retval = -1; int retval = -1;
int options = 0x0; int options = 0x0;
cvec *cvv = NULL; cvec *cvv = NULL;
char *pattern = NULL; cvec *patterns = NULL;
cvec *regexps = NULL;
uint8_t fraction = 0; uint8_t fraction = 0;
yang_stmt *resolved = NULL; yang_stmt *resolved = NULL;
assert(ys->ys_keyword == Y_TYPE); if (yang_keyword_get(ys) != Y_TYPE){
clicon_err(OE_YANG, EINVAL, "Expected Y_TYPE");
goto done;
}
if ((patterns = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
/* Recursively resolve ys -> resolve with restrictions(options, etc) /* Recursively resolve ys -> resolve with restrictions(options, etc)
* Note that the resolved type could be ys itself. * Note that the resolved type could be ys itself.
*/ */
if (yang_type_resolve((yang_stmt*)ys->ys_parent, (yang_stmt*)ys->ys_parent, if (yang_type_resolve(ys->ys_parent, ys->ys_parent,
ys, &resolved, ys, &resolved,
&options, &cvv, &pattern, &fraction) < 0) &options, &cvv, patterns, NULL, &fraction) < 0)
goto done; goto done;
/* Cache the resolve locally */ /* If pattern strings, then compile regexps as well */
if (cvec_len(patterns)){
if ((regexps = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
/* Compile from pattern strings to compiled regexps */
if (compile_pattern2regexp(h, patterns, regexps) < 1)
goto done;
}
/* Cache the type resolving locally. Only place where this is done.
* Why not do it in yang_type_resolve? (compile regexps needs clicon_handle)
*/
if (yang_type_cache_set(&ys->ys_typecache, if (yang_type_cache_set(&ys->ys_typecache,
resolved, options, cvv, pattern, fraction) < 0) resolved, options, cvv,
patterns, regexps,
fraction) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
if (patterns)
cvec_free(patterns);
if (regexps)
cvec_free(regexps);
return retval; return retval;
} }
@ -368,6 +490,48 @@ clicon_type2cv(char *origtype,
return retval; return retval;
} }
/*! Validate CLIgen variable with pattern statements
* @param[in] h Clicon handle
* @param[in] regexps Vector of compiled regexps
* @param[out] reason If given, and return value is 0, contains malloced string
* @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK
*/
static int
cv_validate_pattern(clicon_handle h,
cvec *regexps,
yang_stmt *yrestype,
char *str,
char **reason)
{
int retval = -1;
cg_var *cvr;
void *re = NULL;
int ret;
cvr = NULL; /* Loop over compiled regexps */
while ((cvr = cvec_each(regexps, cvr)) != NULL){
re = cv_void_get(cvr);
if ((ret = regex_exec(h, re, str?str:"")) < 0)
goto done;
if (ret == 0){
if (reason)
*reason = cligen_reason("regexp match fail: pattern does not match %s",
str);
goto fail;
break;
}
}
retval = 1; /* match */
done:
return retval;
fail:
retval = 0; /* validation failed */
goto done;
}
/* cf cligen/cligen_var.c */ /* cf cligen/cligen_var.c */
#define range_check(i, rmin, rmax, type) \ #define range_check(i, rmin, rmax, type) \
((rmin && (i) < cv_##type##_get(rmin)) || \ ((rmin && (i) < cv_##type##_get(rmin)) || \
@ -375,9 +539,17 @@ clicon_type2cv(char *origtype,
/*! Validate CLIgen variable /*! Validate CLIgen variable
* @param[in] h Clicon handle
* @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
* @param[in] cvtype Resolved type of cv
* string describing reason why validation failed.
* @param[in] regexps Vector of compiled regexps
* @param[out] reason If given, and return value is 0, contains malloced str
* @retval -1 Error (fatal), with errno set to indicate error * @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free() * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK * @retval 1 Validation OK
* @note reason if given must be freed by caller
*/ */
static int static int
cv_validate1(clicon_handle h, cv_validate1(clicon_handle h,
@ -385,7 +557,7 @@ cv_validate1(clicon_handle h,
enum cv_type cvtype, enum cv_type cvtype,
int options, int options,
cvec *cvv, cvec *cvv,
char *pattern, cvec *regexps,
yang_stmt *yrestype, yang_stmt *yrestype,
char *restype, char *restype,
char **reason) char **reason)
@ -554,30 +726,12 @@ cv_validate1(clicon_handle h,
} }
} }
} }
if ((options & YANG_OPTIONS_PATTERN) != 0) { if (regexps && cvec_len(regexps)) {
void *re = NULL; if ((ret = cv_validate_pattern(h, regexps, yrestype, str, reason)) < 0)
if ((re = yang_regex_cache_get(yrestype)) == NULL){ goto done;
if ((ret = regex_compile(h, pattern, &re)) < 0) if (ret == 0)
goto done;
if (ret == 0){
if (reason)
*reason = cligen_reason("regexp compile fail: \"%s\"",
pattern);
goto fail;
break;
}
yang_regex_cache_set(yrestype, re);
}
if ((ret = regex_exec(h, re, str?str:"")) < 0)
goto done;
if (ret == 0){
if (reason)
*reason = cligen_reason("regexp match fail: \"%s\" does not match %s",
str, pattern);
goto fail; goto fail;
break; }
}
}
break; break;
case CGV_VOID: case CGV_VOID:
break; /* empty type OK */ break; /* empty type OK */
@ -605,29 +759,34 @@ static int ys_cv_validate_union(clicon_handle h,yang_stmt *ys, char **reason,
yang_stmt *yrestype, char *type, char *val); yang_stmt *yrestype, char *type, char *val);
/*! /*!
* @param[out] reason If given and return val is 0, contains a malloced string
* @retval -1 Error (fatal), with errno set to indicate error * @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free() * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK * @retval 1 Validation OK
*/ */
static int static int
ys_cv_validate_union_one(clicon_handle h, ys_cv_validate_union_one(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
char **reason, char **reason,
yang_stmt *yt, yang_stmt *yt,
char *type, /* orig type */ char *type, /* orig type */
char *val) char *val)
{ {
int retval = -1; int retval = -1;
yang_stmt *yrt; /* union subtype */ yang_stmt *yrt; /* union subtype */
int options = 0; int options = 0;
cvec *cvv = NULL; cvec *cvv = NULL;
char *pattern = NULL; cvec *regexps = NULL;
uint8_t fraction = 0; uint8_t fraction = 0;
char *restype; char *restype;
enum cv_type cvtype; enum cv_type cvtype;
cg_var *cvt=NULL; cg_var *cvt=NULL;
if (yang_type_resolve(ys, ys, yt, &yrt, &options, &cvv, &pattern, if ((regexps = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (yang_type_resolve(ys, ys, yt, &yrt, &options, &cvv, NULL, regexps,
&fraction) < 0) &fraction) < 0)
goto done; goto done;
restype = yrt?yrt->ys_argument:NULL; restype = yrt?yrt->ys_argument:NULL;
@ -650,16 +809,19 @@ ys_cv_validate_union_one(clicon_handle h,
if (retval == 0) if (retval == 0)
goto done; goto done;
if ((retval = cv_validate1(h, cvt, cvtype, options, cvv, if ((retval = cv_validate1(h, cvt, cvtype, options, cvv,
pattern, yrt, restype, reason)) < 0) regexps, yrt, restype, reason)) < 0)
goto done; goto done;
} }
done: done:
if (regexps)
cvec_free(regexps);
if (cvt) if (cvt)
cv_free(cvt); cv_free(cvt);
return retval; return retval;
} }
/*! /*!
* @param[out] reason If given, and return value is 0, contains malloced string
* @retval -1 Error (fatal), with errno set to indicate error * @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free() * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK * @retval 1 Validation OK
@ -705,26 +867,28 @@ ys_cv_validate_union(clicon_handle h,
/*! Validate cligen variable cv using yang statement as spec /*! Validate cligen variable cv using yang statement as spec
* *
* @param[in] h Clicon handle
* @param[in] cv A cligen variable to validate. This is a correctly parsed cv. * @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
* @param[in] ys A yang statement, must be leaf or leaf-list. * @param[in] ys A yang statement, must be leaf or leaf-list.
* @param[out] reason If given, and if return value is 0, contains a malloced string * @param[out] reason If given, and if return value is 0, contains malloced
* describing the reason why the validation failed. Must be freed. * string describing reason why validation failed.
* @retval -1 Error (fatal), with errno set to indicate error * @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free() * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK * @retval 1 Validation OK
* See also cv_validate - the code is similar. * See also cv_validate - the code is similar.
* @note reason if given must be freed by caller
*/ */
int int
ys_cv_validate(clicon_handle h, ys_cv_validate(clicon_handle h,
cg_var *cv, cg_var *cv,
yang_stmt *ys, yang_stmt *ys,
char **reason) char **reason)
{ {
int retval = -1; int retval = -1;
cg_var *ycv; /* cv of yang-statement */ cg_var *ycv; /* cv of yang-statement */
int options = 0; int options = 0;
cvec *cvv = NULL; cvec *cvv = NULL;
char *pattern = NULL; cvec *regexps = NULL;
enum cv_type cvtype; enum cv_type cvtype;
char *type; /* orig type */ char *type; /* orig type */
yang_stmt *yrestype; /* resolved type */ yang_stmt *yrestype; /* resolved type */
@ -741,8 +905,14 @@ ys_cv_validate(clicon_handle h,
goto done; goto done;
} }
ycv = ys->ys_cv; ycv = ys->ys_cv;
if ((regexps = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (yang_type_get(ys, &type, &yrestype, if (yang_type_get(ys, &type, &yrestype,
&options, &cvv, &pattern, &fraction) < 0) &options, &cvv,
NULL, regexps,
&fraction) < 0)
goto done; goto done;
restype = yrestype?yrestype->ys_argument:NULL; restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(type, restype, ys, &cvtype) < 0) if (clicon_type2cv(type, restype, ys, &cvtype) < 0)
@ -767,10 +937,12 @@ ys_cv_validate(clicon_handle h,
retval = retval2; /* invalid (0) with latest reason or valid 1 */ retval = retval2; /* invalid (0) with latest reason or valid 1 */
} }
else else
if ((retval = cv_validate1(h, cv, cvtype, options, cvv, pattern, if ((retval = cv_validate1(h, cv, cvtype, options, cvv,
yrestype, restype, reason)) < 0) regexps, yrestype, restype, reason)) < 0)
goto done; goto done;
done: done:
if (regexps)
cvec_free(regexps);
if (cvt) if (cvt)
cv_free(cvt); cv_free(cvt);
return retval; return retval;
@ -876,45 +1048,63 @@ yang_find_identity(yang_stmt *ys,
return yid; return yid;
} }
/*! Resolve type restrictions, return contraining parameters /*! Resolve type restrictions, return constraining parameters
* @param[in] yrange Yang type range restriction if any *
* @param[in] ylength Yang type length restriction if any * This is for types with range/length/regexp restrictions of the base type
* @param[in] ypattern Yang type pattern restriction if any * Also fraction-digits for decimal64 is handled as that.
* @param[in] yfraction Yang type fraction restriction if any * @param[in] ytype yang-stmt object containing currently resolving type
* @param[out] options Pointer to flags field of optional values. optional * @param[out] options Pointer to flags field of optional values. optional
* @param[out] cvv Pointer to cvec with min range or length. * @param[out] cvv Pointer to cvec with min range or length.
* If options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH * If options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH
* @param[out] pattern Pointer to static string of yang string pattern. optional * @param[out] regexps Pointer to cvec of compiled patterns
* @param[out] fraction For decimal64, how many digits after period * @param[out] fraction For decimal64, how many digits after period
* @retval 0 OK. * @retval -1 Error
* @retval 0 OK.
*/ */
static int static int
resolve_restrictions(yang_stmt *yrange, resolve_restrictions(yang_stmt *ytype,
yang_stmt *ylength,
yang_stmt *ypattern,
yang_stmt *yfraction,
int *options, int *options,
cvec **cvv, cvec **cvv,
char **pattern, cvec *regexps,
uint8_t *fraction) uint8_t *fraction)
{ {
if (options && cvv && yrange != NULL){ int retval = -1;
*cvv = yrange->ys_cvec; yang_stmt *ys;
cg_var *cv;
char *pattern;
if (options && cvv &&
(ys = yang_find(ytype, Y_RANGE, NULL)) != NULL){
*cvv = ys->ys_cvec;
*options |= YANG_OPTIONS_RANGE; *options |= YANG_OPTIONS_RANGE;
} }
if (options && cvv && ylength != NULL){ if (options && cvv &&
*cvv = ylength->ys_cvec; (ys = yang_find(ytype, Y_LENGTH, NULL)) != NULL){
*cvv = ys->ys_cvec;
*options |= YANG_OPTIONS_LENGTH; *options |= YANG_OPTIONS_LENGTH;
} }
if (options && pattern && ypattern != NULL){ /* Find all patterns */
*pattern = ypattern->ys_argument; if (options && regexps){
*options |= YANG_OPTIONS_PATTERN; ys = NULL;
while ((ys = yn_each(ytype, ys)) != NULL) {
if (yang_keyword_get(ys) != Y_PATTERN)
continue;
if ((cv = cvec_add(regexps, CGV_STRING)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_add");
goto done;
}
pattern = ys->ys_argument; /* clear text pattern */
cv_string_set(cv, pattern);
}
} }
if (options && fraction && yfraction != NULL){ if (options && fraction &&
*fraction = cv_uint8_get(yfraction->ys_cv); (ys = yang_find(ytype, Y_FRACTION_DIGITS, NULL)) != NULL){
*fraction = cv_uint8_get(ys->ys_cv);
*options |= YANG_OPTIONS_FRACTION_DIGITS; *options |= YANG_OPTIONS_FRACTION_DIGITS;
} }
return 0; retval = 0;
done:
return retval;
} }
/*! Recursively resolve a yang type to built-in type with optional restrictions /*! Recursively resolve a yang type to built-in type with optional restrictions
@ -926,8 +1116,8 @@ resolve_restrictions(yang_stmt *yrange,
* @param[out] cvv Cvec with min/max range or length. * @param[out] cvv Cvec with min/max range or length.
* Present if options&YANG_OPTIONS_RANGE|_LENGTH. * Present if options&YANG_OPTIONS_RANGE|_LENGTH.
* Can be a vector if multiple ranges * Can be a vector if multiple ranges
* @param[out] pattern String of POSIX regexp pattern * @param[out] patterns Initialized cvec of regexp patterns strings (if any)
* Present if options&YANG_OPTIONS_PATTERN * @param[out] regexps Initialized cvec of compiled regexps (if any)
* @param[out] fraction for decimal64, how many digits after period * @param[out] fraction for decimal64, how many digits after period
* Present if options&YANG_OPTIONS_FRACTION_DIGITS * Present if options&YANG_OPTIONS_FRACTION_DIGITS
* @retval 0 OK. Note yrestype may still be NULL. * @retval 0 OK. Note yrestype may still be NULL.
@ -935,8 +1125,8 @@ resolve_restrictions(yang_stmt *yrange,
* The setting of the options argument has the following semantics: * The setting of the options argument has the following semantics:
* options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing * options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
* array of range_min, range_max cv:s * array of range_min, range_max cv:s
* options&YANG_OPTIONS_PATTERN --> pattern is set
* options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set * options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set
* patterns && cvec_len(patterns) --> there are patterns
* Note that the static output strings (type, pattern) should be copied if used asap. * Note that the static output strings (type, pattern) should be copied if used asap.
* Note also that for all pointer arguments, if NULL is given, no value is assigned. * Note also that for all pointer arguments, if NULL is given, no value is assigned.
*/ */
@ -947,15 +1137,12 @@ yang_type_resolve(yang_stmt *yorig,
yang_stmt **yrestype, yang_stmt **yrestype,
int *options, int *options,
cvec **cvv, cvec **cvv,
char **pattern, cvec *patterns,
cvec *regexps,
uint8_t *fraction) uint8_t *fraction)
{ {
yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */ yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */
yang_stmt *rytype; /* Resolved type of ytype */ yang_stmt *rytype; /* Resolved type of ytype */
yang_stmt *yrange;
yang_stmt *ylength;
yang_stmt *ypattern;
yang_stmt *yfraction;
char *type; char *type;
char *prefix = NULL; char *prefix = NULL;
int retval = -1; int retval = -1;
@ -968,23 +1155,18 @@ yang_type_resolve(yang_stmt *yorig,
type = yarg_id(ytype); /* This is the type to resolve */ type = yarg_id(ytype); /* This is the type to resolve */
prefix = yarg_prefix(ytype); /* And this its prefix */ prefix = yarg_prefix(ytype); /* And this its prefix */
/* Cache does not work for eg string length 32? */ /* Cache does not work for eg string length 32? */
if (!yang_builtin(type) && ytype->ys_typecache != NULL){ if (/*!yang_builtin(type) &&*/ ytype->ys_typecache != NULL){
if (yang_type_cache_get(ytype->ys_typecache, yrestype, if (yang_type_cache_get(ytype->ys_typecache, yrestype,
options, cvv, pattern, fraction) < 0) options, cvv, patterns, regexps, fraction) < 0)
goto done; goto done;
goto ok; goto ok;
} }
/* Resolving type restrictions */
yrange = yang_find(ytype, Y_RANGE, NULL);
ylength = yang_find(ytype, Y_LENGTH, NULL);
ypattern = yang_find(ytype, Y_PATTERN, NULL);
yfraction = yang_find(ytype, Y_FRACTION_DIGITS, NULL);
/* Check if type is basic type. If so, return that */ /* Check if type is basic type. If so, return that */
if (prefix == NULL && yang_builtin(type)){ if ((prefix == NULL && yang_builtin(type))){
*yrestype = ytype; *yrestype = ytype;
resolve_restrictions(yrange, ylength, ypattern, yfraction, options, if (resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0)
cvv, pattern, fraction); goto done;
goto ok; goto ok;
} }
@ -1023,11 +1205,13 @@ yang_type_resolve(yang_stmt *yorig,
} }
/* recursively resolve this new type */ /* recursively resolve this new type */
if (yang_type_resolve(yorig, ys, rytype, yrestype, if (yang_type_resolve(yorig, ys, rytype, yrestype,
options, cvv, pattern, fraction) < 0) options, cvv,
patterns, regexps,
fraction) < 0)
goto done;
/* appends patterns, overwrites others if any */
if (resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0)
goto done; goto done;
/* overwrites the resolved if any */
resolve_restrictions(yrange, ylength, ypattern, yfraction, options,
cvv, pattern, fraction);
} }
ok: ok:
retval = 0; retval = 0;
@ -1043,17 +1227,17 @@ yang_type_resolve(yang_stmt *yorig,
* yang_stmt *yrestype; * yang_stmt *yrestype;
* int options; * int options;
* cvec *cvv = NULL; * cvec *cvv = NULL;
* char *pattern; * cvec *patterns = cvec_new(0);
* cvec *regexps = cvec_new(0);
* uint8_t fraction; * uint8_t fraction;
* *
* if (yang_type_get(ys, &type, &yrestype, &options, &cvv, &pattern, &fraction) < 0) * if (yang_type_get(ys, &type, &yrestype, &options, &cvv,
* patterns, regexps, &fraction) < 0)
* goto err; * goto err;
* if (yrestype == NULL) # unresolved * if (yrestype == NULL) # unresolved
* goto err; * goto err;
* if (options & YANG_OPTIONS_LENGTH != 0) * if (options & YANG_OPTIONS_LENGTH != 0)
* printf("%d..%d\n", min , max); * printf("%d..%d\n", min , max);
* if (options & YANG_OPTIONS_PATTERN != 0)
* printf("regexp: %s\n", pattern);
* @endcode * @endcode
* @param[in] ys yang-stmt, leaf or leaf-list * @param[in] ys yang-stmt, leaf or leaf-list
* @param[out] origtype original type may be derived or built-in * @param[out] origtype original type may be derived or built-in
@ -1062,8 +1246,8 @@ yang_type_resolve(yang_stmt *yorig,
* @param[out] cvv Cvec with min/max range or length. * @param[out] cvv Cvec with min/max range or length.
* Present if options&YANG_OPTIONS_RANGE|_LENGTH. * Present if options&YANG_OPTIONS_RANGE|_LENGTH.
* Can be a vector if multiple ranges * Can be a vector if multiple ranges
* @param[out] pattern yang string pattern POSIX regexp patterns * @param[out] pattern yang cvec pattern POSIX regexp patterns
* Present if options&YANG_OPTIONS_PATTERN * @param[out] regexps Initialized cvec of compiled regexps (if any)
* @param[out] fraction for decimal64, how many digits after period * @param[out] fraction for decimal64, how many digits after period
* Present if options&YANG_OPTIONS_FRACTION_DIGITS * Present if options&YANG_OPTIONS_FRACTION_DIGITS
* @retval 0 OK, but note that restype==NULL means not resolved. * @retval 0 OK, but note that restype==NULL means not resolved.
@ -1071,7 +1255,6 @@ yang_type_resolve(yang_stmt *yorig,
* The setting of the options argument has the following semantics: * The setting of the options argument has the following semantics:
* options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing * options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
* array of range_min, range_max cv:s * array of range_min, range_max cv:s
* options&YANG_OPTIONS_PATTERN --> pattern is set
* options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set * options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set
* Note that the static output strings (type, pattern) should be copied if used asap. * Note that the static output strings (type, pattern) should be copied if used asap.
* Note also that for all pointer arguments, if NULL is given, no value is assigned. * Note also that for all pointer arguments, if NULL is given, no value is assigned.
@ -1083,7 +1266,8 @@ yang_type_get(yang_stmt *ys,
yang_stmt **yrestype, yang_stmt **yrestype,
int *options, int *options,
cvec **cvv, cvec **cvv,
char **pattern, cvec *patterns,
cvec *regexps,
uint8_t *fraction uint8_t *fraction
) )
{ {
@ -1103,7 +1287,7 @@ yang_type_get(yang_stmt *ys,
if (origtype) if (origtype)
*origtype = type; *origtype = type;
if (yang_type_resolve(ys, ys, ytype, yrestype, if (yang_type_resolve(ys, ys, ytype, yrestype,
options, cvv, pattern, fraction) < 0) options, cvv, patterns, regexps, fraction) < 0)
goto done; goto done;
clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type, clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type,
*yrestype?(*yrestype)->ys_argument:"null"); *yrestype?(*yrestype)->ys_argument:"null");

File diff suppressed because one or more lines are too long

View file

@ -151,7 +151,7 @@ new "netconf NONEXIST subscription"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>NONEXIST</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></rpc-error></rpc-reply>]]>]]>$' $NCWAIT expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>NONEXIST</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></rpc-error></rpc-reply>]]>]]>$' $NCWAIT
new "netconf EXAMPLE subscription with wrong date" new "netconf EXAMPLE subscription with wrong date"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail: "kallekaka" does not match' 0 expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:' 0
#new "netconf EXAMPLE subscription with replay" #new "netconf EXAMPLE subscription with replay"
#NOW=$(date +"%Y-%m-%dT%H:%M:%S") #NOW=$(date +"%Y-%m-%dT%H:%M:%S")

View file

@ -200,7 +200,7 @@ EOF
# 1: dbcache true/false # 1: dbcache true/false
testrun(){ testrun(){
dbcache=$1 dbcache=$1
new "test params: -f $cfg -y $fyang # dbcache: $dbcache" new "test params: -f $cfg # dbcache: $dbcache"
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -208,6 +208,7 @@ testrun(){
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -226,379 +227,379 @@ EOF
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
start_backend -s init -f $cfg -y $fyang start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi fi
new "cli set transitive string. type is alpha followed by number and is defined in three levels of modules" new "cli set transitive string. type is alpha followed by number and is defined in three levels of modules"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle x99" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set c talle x99" 0 '^$'
new "cli set transitive string error. Wrong type" new "cli set transitive string error. Wrong type"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle 9xx" 255 '^CLI syntax error: "set c talle 9xx": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set c talle 9xx" 255 '^CLI syntax error: "set c talle 9xx": Unknown command$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf set transitive string error" new "netconf set transitive string error"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><c xmlns="urn:example:clixon"><talle>9xx</talle></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><c xmlns="urn:example:clixon"><talle>9xx</talle></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>"
new "netconf validate should fail" new "netconf validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>talle</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail: "9xx" does not match \[a-z\]\[0-9\]\*</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>talle</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "cli set transitive union int (ulle should accept 4.44|bounded|unbounded)" new "cli set transitive union int (ulle should accept 4.44|bounded|unbounded)"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 33" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set c ulle 33" 0 '^$'
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o -l o validate" 0 '^$'
new "cli set transitive union string (and space)" new "cli set transitive union string (and space)"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle un\ bounded" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set c ulle un\ bounded" 0 '^$'
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o -l o validate" 0 '^$'
new "cli set transitive union error. should fail" new "cli set transitive union error. should fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle kalle" 255 '^CLI syntax error: "set c ulle kalle": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set c ulle kalle" 255 '^CLI syntax error: "set c ulle kalle": Unknown command$'
new "cli set transitive union error int" new "cli set transitive union error int"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 55" 255 '^CLI syntax error: "set c ulle 55": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set c ulle 55" 255 '^CLI syntax error: "set c ulle 55": Unknown command$'
new "netconf set transitive union error int" new "netconf set transitive union error int"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><c xmlns="urn:example:clixon"><ulle>55</ulle></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><c xmlns="urn:example:clixon"><ulle>55</ulle></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>"
new "netconf validate should fail" new "netconf validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>ulle</bad-element></error-info><error-severity>error</error-severity><error-message>'55' does not match enumeration</error-message></rpc-error></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>ulle</bad-element></error-info><error-severity>error</error-severity><error-message>'55' does not match enumeration</error-message></rpc-error></rpc-reply>]]>]]>$"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#----------- #-----------
new "cli set ab" new "cli set ab"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.a.b" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set list a.b.a.b" 0 '^$'
new "cli set cd" new "cli set cd"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list c.d.c.d" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set list c.d.c.d" 0 '^$'
new "cli set ef" new "cli set ef"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list e.f.e.f" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set list e.f.e.f" 0 '^$'
new "cli set ab fail" new "cli set ab fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a&b&a&b" 255 "^CLI syntax error" expectfn "$clixon_cli -1f $cfg -l o set list a&b&a&b" 255 "^CLI syntax error"
new "cli set ad fail" new "cli set ad fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.c.d" 255 "^CLI syntax error" expectfn "$clixon_cli -1f $cfg -l o set list a.b.c.d" 255 "^CLI syntax error"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o -l o validate" 0 '^$'
new "cli commit" new "cli commit"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o commit" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o -l o commit" 0 '^$'
new "netconf validate ok" new "netconf validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf set ab wrong" new "netconf set ab wrong"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><list xmlns="urn:example:clixon"><ip>a.b&amp; c.d</ip></list></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><list xmlns="urn:example:clixon"><ip>a.b&amp; c.d</ip></list></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "cli enum value" new "cli enum value"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set status down" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set status down" 0 '^$'
new "cli bits value" new "cli bits value"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set mbits create" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set mbits create" 0 '^$'
#XXX No, cli cant assign two bit values #XXX No, cli cant assign two bit values
#new "cli bits two values" #new "cli bits two values"
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set mbits \"create read\"" 0 '^$' #expectfn "$clixon_cli -1f $cfg -l o set mbits \"create read\"" 0 '^$'
new "netconf bits two values" new "netconf bits two values"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><mbits xmlns="urn:example:clixon">create read</mbits></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><mbits xmlns="urn:example:clixon">create read</mbits></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "cli bits validate" new "cli bits validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o validate" 0 '^$'
#-------- num0 empty value #-------- num0 empty value
new "netconf num0 no value" new "netconf num0 no value"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num0 xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num0 xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate no value wrong" new "netconf validate no value wrong"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num0</bad-element></error-info><error-severity>error</error-severity><error-message>Invalid NULL value</error-message></rpc-error></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num0</bad-element></error-info><error-severity>error</error-severity><error-message>Invalid NULL value</error-message></rpc-error></rpc-reply>]]>]]>'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- num1 single range (1) #-------- num1 single range (1)
new "cli range test num1 1 OK" new "cli range test num1 1 OK"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 1" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set num1 1" 0 '^$'
#new "cli range test num1 -100 ok" # XXX -/minus cant be given as argv #new "cli range test num1 -100 ok" # XXX -/minus cant be given as argv
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 \-100" 0 '^$' #expectfn "$clixon_cli -1f $cfg -l o set num1 \-100" 0 '^$'
new "cli range test num1 2 error" new "cli range test num1 2 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 2" 255 '^CLI syntax error: "set num1 2": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set num1 2" 255 '^CLI syntax error: "set num1 2": Unknown command$'
new "netconf range set num1 -1" new "netconf range set num1 -1"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num1 xmlns="urn:example:clixon">-1</num1></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num1 xmlns="urn:example:clixon">-1</num1></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num1 -1 wrong" new "netconf validate num1 -1 wrong"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num1</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range: -1</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num1</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range: -1</error-message></rpc-error></rpc-reply>]]>]]>$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- num2 range and blanks #-------- num2 range and blanks
new "cli range test num2 3 error" new "cli range test num2 3 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num2 3" 255 '^CLI syntax error: "set num2 3": Number out of range: 3$' expectfn "$clixon_cli -1f $cfg -l o set num2 3" 255 '^CLI syntax error: "set num2 3": Number out of range: 3$'
new "cli range test num2 1000 ok" new "cli range test num2 1000 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num2 1000" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set num2 1000" 0 '^$'
new "cli range test num2 5000 error" new "cli range test num2 5000 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num2 5000" 255 '^CLI syntax error: "set num2 5000": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set num2 5000" 255 '^CLI syntax error: "set num2 5000": Unknown command$'
new "netconf range set num2 3 fail" new "netconf range set num2 3 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num2 xmlns="urn:example:clixon">3</num2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num2 xmlns="urn:example:clixon">3</num2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num2 3 fail" new "netconf validate num2 3 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num2</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range: 3</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num2</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range: 3</error-message></rpc-error></rpc-reply>]]>]]>$'
new "netconf range set num2 1000 ok" new "netconf range set num2 1000 ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num2 xmlns="urn:example:clixon">1000</num2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num2 xmlns="urn:example:clixon">1000</num2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num2 1000 ok" new "netconf validate num2 1000 ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range set num2 5000 fail" new "netconf range set num2 5000 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num2 xmlns="urn:example:clixon">5000</num2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num2 xmlns="urn:example:clixon">5000</num2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num2 5000 fail" new "netconf validate num2 5000 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num2</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range: 5000</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num2</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range: 5000</error-message></rpc-error></rpc-reply>]]>]]>$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- num3 min max range #-------- num3 min max range
new "cli range test num3 42 ok" new "cli range test num3 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num3 42" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set num3 42" 0 '^$'
new "cli range test num3 260 fail" new "cli range test num3 260 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num3 260" 255 '^CLI syntax error: "set num3 260": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set num3 260" 255 '^CLI syntax error: "set num3 260": Unknown command$'
new "cli range test num3 -1 fail" new "cli range test num3 -1 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num3 -1" 255 "CLI syntax error:" expectfn "$clixon_cli -1f $cfg -l o set num3 -1" 255 "CLI syntax error:"
new "netconf range set num3 260 fail" new "netconf range set num3 260 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num3 xmlns="urn:example:clixon">260</num3></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num3 xmlns="urn:example:clixon">260</num3></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num3 260 fail" new "netconf validate num3 260 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num3</bad-element></error-info><error-severity>error</error-severity><error-message>260 is out of range(type is uint8)</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num3</bad-element></error-info><error-severity>error</error-severity><error-message>260 is out of range(type is uint8)</error-message></rpc-error></rpc-reply>]]>]]>$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- num4 multiple ranges 1..2 | 42..50 #-------- num4 multiple ranges 1..2 | 42..50
new "cli range test num4 multiple 0 fail" new "cli range test num4 multiple 0 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 0" 255 '^CLI syntax error: "set num4 0": Number out of range: 0$' expectfn "$clixon_cli -1f $cfg -l o set num4 0" 255 '^CLI syntax error: "set num4 0": Number out of range: 0$'
new "cli range test num4 multiple 2 ok" new "cli range test num4 multiple 2 ok"
expectfn "$clixon_cli -1f $cfg -l e -y $fyang set num4 2" 0 '^$' expectfn "$clixon_cli -1f $cfg -l e set num4 2" 0 '^$'
new "cli range test num4 multiple 20 fail" new "cli range test num4 multiple 20 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 20" 255 '^CLI syntax error: "set num4 20": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set num4 20" 255 '^CLI syntax error: "set num4 20": Unknown command$'
new "cli range test num4 multiple 42 ok" new "cli range test num4 multiple 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 42" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set num4 42" 0 '^$'
new "cli range test num4 multiple 99 fail" new "cli range test num4 multiple 99 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 99" 255 '^CLI syntax error: "set num4 99": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set num4 99" 255 '^CLI syntax error: "set num4 99": Unknown command$'
new "netconf range set num4 multiple 2" new "netconf range set num4 multiple 2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num4 OK" new "netconf validate num4 OK"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range set num4 multiple 20" new "netconf range set num4 multiple 20"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num4 fail" new "netconf validate num4 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range set num4 multiple 42" new "netconf range set num4 multiple 42"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate num4 fail" new "netconf validate num4 fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- dec64 multiple ranges -3.5..-2.5 | 0.0 | 10.0..20.0 #-------- dec64 multiple ranges -3.5..-2.5 | 0.0 | 10.0..20.0
# XXX how to enter negative numbers in bash string and cli -1? # XXX how to enter negative numbers in bash string and cli -1?
new "cli range dec64 multiple 0 ok" new "cli range dec64 multiple 0 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set dec 0" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set dec 0" 0 '^$'
new "cli range dec64 multiple 0.1 fail" new "cli range dec64 multiple 0.1 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 0.1" 255 '^CLI syntax error: "set num4 0.1": '"'"'0.1'"'"' is not a number$' expectfn "$clixon_cli -1f $cfg -l o set num4 0.1" 255 '^CLI syntax error: "set num4 0.1": '"'"'0.1'"'"' is not a number$'
new "cli range dec64 multiple 15.0 ok" new "cli range dec64 multiple 15.0 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set dec 15.0" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set dec 15.0" 0 '^$'
new "cli range dec64 multiple 30.0 fail" new "cli range dec64 multiple 30.0 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set dec 30.0" 255 '^CLI syntax error: "set dec 30.0": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set dec 30.0" 255 '^CLI syntax error: "set dec 30.0": Unknown command$'
new "dec64 discard-changes" new "dec64 discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Same with netconf # Same with netconf
new "netconf range dec64 -3.59" new "netconf range dec64 -3.59"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-3.59</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-3.59</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -3.59 validate fail" new "netconf range dec64 -3.59 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
new "netconf range dec64 -3.5" new "netconf range dec64 -3.5"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-3.500</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-3.500</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -3.5 validate ok" new "netconf range dec64 -3.5 validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range dec64 -2" new "netconf range dec64 -2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-2</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-2</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -2 validate fail" new "netconf range dec64 -2 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
new "netconf range dec64 -0.001" new "netconf range dec64 -0.001"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-0.001</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-0.001</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -0.001 validate fail" new "netconf range dec64 -0.001 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
new "netconf range dec64 0.0" new "netconf range dec64 0.0"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">0.0</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">0.0</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 0.0 validate ok" new "netconf range dec64 0.0 validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range dec64 +0.001" new "netconf range dec64 +0.001"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">+0.001</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">+0.001</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 +0.001 validate fail" new "netconf range dec64 +0.001 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
#----------------string ranges--------------------- #----------------string ranges---------------------
#-------- len1 single range (2) #-------- len1 single range (2)
new "cli length test len1 1 fail" new "cli length test len1 1 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len1 x" 255 '^CLI syntax error: "set len1 x": String length not within limits: 1$' expectfn "$clixon_cli -1f $cfg -l o set len1 x" 255 '^CLI syntax error: "set len1 x": String length not within limits: 1$'
new "cli length test len1 2 OK" new "cli length test len1 2 OK"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len1 xy" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set len1 xy" 0 '^$'
new "cli length test len1 3 error" new "cli length test len1 3 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len1 hej" 255 '^CLI syntax error: "set len1 hej": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set len1 hej" 255 '^CLI syntax error: "set len1 hej": Unknown command$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf length set len1 1" new "netconf length set len1 1"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><len1 xmlns="urn:example:clixon">x</len1></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><len1 xmlns="urn:example:clixon">x</len1></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate len1 1 wrong" new "netconf validate len1 1 wrong"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>len1</bad-element></error-info><error-severity>error</error-severity><error-message>string length out of range: 1</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>len1</bad-element></error-info><error-severity>error</error-severity><error-message>string length out of range: 1</error-message></rpc-error></rpc-reply>]]>]]>$'
#-------- len2 range and blanks #-------- len2 range and blanks
new "cli length test len2 3 error" new "cli length test len2 3 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len2 ab" 255 '^CLI syntax error: "set len2 ab": String length not within limits: 2$' expectfn "$clixon_cli -1f $cfg -l o set len2 ab" 255 '^CLI syntax error: "set len2 ab": String length not within limits: 2$'
new "cli length test len2 42 ok" new "cli length test len2 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len2 hejhophdsakjhkjsadhkjsahdkjsad" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set len2 hejhophdsakjhkjsadhkjsahdkjsad" 0 '^$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- len3 min max range #-------- len3 min max range
new "cli range ptest len3 42 ok" new "cli range ptest len3 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 '^$'
#-------- len4 multiple ranges 2..3 | 20-29 #-------- len4 multiple ranges 2..3 | 20-29
new "cli length test len4 1 error" new "cli length test len4 1 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 a" 255 '^CLI syntax error: "set len4 a": String length not within limits: 1$' expectfn "$clixon_cli -1f $cfg -l o set len4 a" 255 '^CLI syntax error: "set len4 a": String length not within limits: 1$'
new "cli length test len4 2 ok" new "cli length test len4 2 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 ab" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set len4 ab" 0 '^$'
new "cli length test len4 10 error" new "cli length test len4 10 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abcdefghij" 255 '^CLI syntax error: "set len4 abcdefghij": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set len4 abcdefghij" 255 '^CLI syntax error: "set len4 abcdefghij": Unknown command$'
new "cli length test len4 20 ok" new "cli length test len4 20 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abcdefghijabcdefghija" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set len4 abcdefghijabcdefghija" 0 '^$'
new "cli length test len4 30 error" new "cli length test len4 30 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abcdefghijabcdefghijabcdefghij" 255 '^CLI syntax error: "set len4 abcdefghijabcdefghijabcdefghij": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set len4 abcdefghijabcdefghijabcdefghij" 255 '^CLI syntax error: "set len4 abcdefghijabcdefghijabcdefghij": Unknown command$'
# XSD schema -> POSIX ECE translation # XSD schema -> POSIX ECE translation
new "cli yang pattern \d ok" new "cli yang pattern \d ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set digit4 0123" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set digit4 0123" 0 '^$'
new "cli yang pattern \d error" new "cli yang pattern \d error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set digit4 01b2" 255 '^CLI syntax error: "set digit4 01b2": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set digit4 01b2" 255 '^CLI syntax error: "set digit4 01b2": Unknown command$'
new "cli yang pattern \w ok" new "cli yang pattern \w ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set word4 abc9" 0 '^$' expectfn "$clixon_cli -1f $cfg -l o set word4 abc9" 0 '^$'
new "cli yang pattern \w error" new "cli yang pattern \w error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set word4 ab%3" 255 '^CLI syntax error: "set word4 ab%3": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set word4 ab%3" 255 '^CLI syntax error: "set word4 ab%3": Unknown command$'
new "netconf pattern \w" new "netconf pattern \w"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><word4 xmlns="urn:example:clixon">aXG9</word4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><word4 xmlns="urn:example:clixon">aXG9</word4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf pattern \w valid" new "netconf pattern \w valid"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf pattern \w error" new "netconf pattern \w error"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><word4 xmlns="urn:example:clixon">ab%d3</word4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><word4 xmlns="urn:example:clixon">ab%d3</word4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf pattern \w valid" new "netconf pattern \w invalid"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>word4</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail: "ab%d3" does not match \\w{4}</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>word4</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#------ minus #------ minus
new "type with minus" new "type with minus"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><minus xmlns="urn:example:clixon">my-name</minus></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><minus xmlns="urn:example:clixon">my-name</minus></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "validate minus" new "validate minus"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#new "cli type with minus" #new "cli type with minus"
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set name my-name" 0 '^$' #expectfn "$clixon_cli -1f $cfg -l o set name my-name" 0 '^$'
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"

View file

@ -192,7 +192,7 @@ main(int argc, char **argv)
xml_print(stderr, x0); xml_print(stderr, x0);
} }
if (sort) if (sort)
xml_sort(xb, NULL); xml_sort(xb, h);
clicon_xml2file(stdout, xb, 0, 0); clicon_xml2file(stdout, xb, 0, 0);
retval = 0; retval = 0;