* 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)
### 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
* According to RFC 7950 7.7.4 and 7.7.5
* See (tests)[test/test_minmax.sh]
@ -54,6 +66,9 @@
### 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
* Just add `clixon_handle h` to all calls.
* Clixon transaction mechanism has changed which may affect your backend plugin callbacks:
@ -141,14 +156,6 @@
### 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
* 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.

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
* 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;
if ((ret = xmldb_put(h, target, operation, xc, username, cbret)) < 0){
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 */
if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
if (xml_apply0(xt, CX_ELMNT, xml_sort, h) < 0)
goto done;
/* Handcraft transition with with only add tree */
td->td_target = xt;

View file

@ -272,6 +272,42 @@ yang2cli_var_range(yang_stmt *ys,
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 */
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys,
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] options Flags field of optional values, see YANG_OPTIONS_*
* @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[out] cb Buffer where cligen code is written
* @see yang_type_resolve for options and other arguments
@ -302,7 +338,7 @@ yang2cli_var_sub(clicon_handle h,
enum cv_type cvtype,
int options,
cvec *cvv,
char *pattern,
cvec *patterns,
uint8_t fraction_digits,
cbuf *cb
)
@ -358,19 +394,9 @@ yang2cli_var_sub(clicon_handle h,
if (yang2cli_var_range(ys, options, cvv, cb) < 0)
goto done;
}
if (options & YANG_OPTIONS_PATTERN){
char *mode;
mode = clicon_yang_regexp(h);
if (strcmp(mode, "posix") == 0){
char *posix = NULL;
if (regexp_xsd2posix(pattern, &posix) < 0)
if (patterns && cvec_len(patterns)){
if (yang2cli_var_pattern(h, patterns, cb) < 0)
goto done;
cprintf(cb, " regexp:\"%s\"", posix);
if (posix)
free(posix);
}
else
cprintf(cb, " regexp:\"%s\"", pattern);
}
cprintf(cb, ">");
if (helptext)
@ -402,16 +428,20 @@ yang2cli_var_union_one(clicon_handle h,
int retval = -1;
int options = 0;
cvec *cvv = NULL;
char *pattern = NULL;
cvec *patterns = NULL;
uint8_t fraction_digits = 0;
enum cv_type cvtype;
yang_stmt *ytype; /* resolved type */
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 */
if (yang_type_resolve(ys, ys, ytsub, /* in */
&ytype, &options, /* resolved type */
&cvv, &pattern, &fraction_digits) < 0)
&cvv, patterns, NULL, &fraction_digits) < 0)
goto done;
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)
goto done;
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;
}
retval = 0;
done:
if (patterns)
cvec_free(patterns);
return retval;
}
@ -494,15 +526,19 @@ yang2cli_var(clicon_handle h,
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */
cvec *cvv = NULL;
char *pattern = NULL;
cvec *patterns = NULL;
uint8_t fraction_digits = 0;
enum cv_type cvtype;
int options = 0;
int completionp;
char *type;
if ((patterns = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (yang_type_get(ys, &origtype, &yrestype,
&options, &cvv, &pattern, &fraction_digits) < 0)
&options, &cvv, patterns, NULL, &fraction_digits) < 0)
goto done;
restype = yrestype?yang_argument_get(yrestype):NULL;
@ -539,7 +575,7 @@ yang2cli_var(clicon_handle h,
if (completionp)
cprintf(cb, "(");
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;
if (completionp){
if (cli_expand_var_generate(h, ys, cvtype,
@ -552,6 +588,8 @@ yang2cli_var(clicon_handle h,
}
retval = 0;
done:
if (patterns)
cvec_free(patterns);
return retval;
}

View file

@ -153,8 +153,6 @@ char *yang_argument_get(yang_stmt *ys);
cg_var *yang_cv_get(yang_stmt *ys);
cvec *yang_cvec_get(yang_stmt *ys);
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 */
yang_stmt *yspec_new(void);

View file

@ -43,8 +43,7 @@
*/
#define YANG_OPTIONS_LENGTH 0x01
#define YANG_OPTIONS_RANGE 0x02
#define YANG_OPTIONS_PATTERN 0x04
#define YANG_OPTIONS_FRACTION_DIGITS 0x08
#define YANG_OPTIONS_FRACTION_DIGITS 0x04
/*
* Types
@ -57,10 +56,11 @@ typedef struct yang_type_cache yang_type_cache;
*/
int yang_type_cache_set(yang_type_cache **ycache,
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 *options, cvec **cvv, char **pattern,
uint8_t *fraction);
int *options, cvec **cvv, cvec *patterns,
cvec *regexps, uint8_t *fraction);
int yang_type_cache_cp(yang_type_cache **ycnew, yang_type_cache *ycold);
int yang_type_cache_free(yang_type_cache *ycache);
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 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 *options, cvec **cvv, char **pattern,
int *options, cvec **cvv,
cvec *patterns, cvec *regexps,
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,
cvec **cvv, char **pattern, uint8_t *fraction);
cvec **cvv, cvec *patterns, cvec *regexps,
uint8_t *fraction);
#endif /* _CLIXON_YANG_TYPE_H_ */

View file

@ -437,7 +437,7 @@ xmldb_get_nocache(clicon_handle h,
goto done;
/* 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;
#if 0 /* debug */
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
@ -542,7 +542,7 @@ xmldb_get_cache(clicon_handle h,
goto done;
/* x1t is wrong here should be <config><system>.. but is <system>.. */
/* 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;
/* 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);
}
/* 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;
if (debug>1)
clicon_xml2file(stderr, x0t, 0, 1);

View file

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

View file

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

View file

@ -2394,51 +2394,3 @@ clicon_log_xml(int level,
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)
goto done;
if (yang_type_resolve(ys, ys, ytype, &yrestype,
NULL, NULL, NULL, NULL) < 0)
NULL, NULL, NULL, NULL, NULL) < 0)
goto done;
if (yrestype==NULL || strcmp(yrestype->ys_argument, "enumeration"))
goto done;

View file

@ -95,7 +95,7 @@ xml_cv_cache(cxobj *x,
goto ok;
if ((y = xml_spec(x)) == NULL)
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;
yang2cv_type(yang_argument_get(yrestype), &cvtype);
if (cvtype==CGV_ERR){

View file

@ -239,30 +239,6 @@ yang_cvec_set(yang_stmt *ys,
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 */
/*! Create new yang specification
@ -307,17 +283,6 @@ ys_new(enum rfc_6020 keyw)
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 */
static int
ys_free1(yang_stmt *ys)
@ -332,7 +297,6 @@ ys_free1(yang_stmt *ys)
cvec_free(ys->ys_cvec);
if (ys->ys_typecache)
yang_type_cache_free(ys->ys_typecache);
yang_regex_cache_free(ys);
free(ys);
return 0;
}
@ -1344,8 +1308,8 @@ yang_print_cbuf(cbuf *cb,
* @retval -1 Error with clicon_err called
*/
static int
ys_populate_leaf(yang_stmt *ys,
void *arg)
ys_populate_leaf(clicon_handle h,
yang_stmt *ys)
{
int retval = -1;
cg_var *cv = NULL;
@ -1363,7 +1327,7 @@ ys_populate_leaf(yang_stmt *ys,
yparent = ys->ys_parent; /* Find parent: list/container */
/* 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)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
@ -1416,8 +1380,8 @@ ys_populate_leaf(yang_stmt *ys,
}
static int
ys_populate_list(yang_stmt *ys,
void *arg)
ys_populate_list(clicon_handle h,
yang_stmt *ys)
{
yang_stmt *ykey;
@ -1523,8 +1487,8 @@ range_parse(yang_stmt *ys,
* ascending order
*/
static int
ys_populate_range(yang_stmt *ys,
void *arg)
ys_populate_range(clicon_handle h,
yang_stmt *ys)
{
int retval = -1;
yang_stmt *yparent; /* type */
@ -1541,7 +1505,7 @@ ys_populate_range(yang_stmt *ys,
goto done;
}
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;
restype = yrestype?yrestype->ys_argument:NULL;
origtype = yarg_id((yang_stmt*)yparent);
@ -1572,8 +1536,8 @@ ys_populate_range(yang_stmt *ys,
* be disjoint and MUST be in ascending order.
*/
static int
ys_populate_length(yang_stmt *ys,
void *arg)
ys_populate_length(clicon_handle h,
yang_stmt *ys)
{
int retval = -1;
yang_stmt *yparent; /* type */
@ -1598,8 +1562,9 @@ ys_populate_length(yang_stmt *ys,
* @
*/
static int
ys_populate_type(yang_stmt *ys,
void *arg)
ys_populate_type(clicon_handle h,
yang_stmt *ys)
{
int retval = -1;
yang_stmt *ybase;
@ -1636,7 +1601,8 @@ ys_populate_type(yang_stmt *ys,
* @see validate_identityref which in runtime validates actual values
*/
static int
ys_populate_identity(yang_stmt *ys,
ys_populate_identity(clicon_handle h,
yang_stmt *ys,
char *idref)
{
int retval = -1;
@ -1695,7 +1661,7 @@ ys_populate_identity(yang_stmt *ys,
cv = NULL;
}
/* Transitive to the root */
if (ys_populate_identity(ybaseid, idref) < 0)
if (ys_populate_identity(h, ybaseid, idref) < 0)
goto done;
}
retval = 0;
@ -1800,7 +1766,8 @@ ys_populate_feature(clicon_handle h,
/*! Populate the unique statement with a cvec
*/
static int
ys_populate_unique(yang_stmt *ys)
ys_populate_unique(clicon_handle h,
yang_stmt *ys)
{
if (ys->ys_cvec)
cvec_free(ys->ys_cvec);
@ -1812,7 +1779,8 @@ ys_populate_unique(yang_stmt *ys)
/*! Populate unknown node with extension
*/
static int
ys_populate_unknown(yang_stmt *ys)
ys_populate_unknown(clicon_handle h,
yang_stmt *ys)
{
int retval = -1;
int cvret;
@ -1865,24 +1833,24 @@ ys_populate(yang_stmt *ys,
void *arg)
{
int retval = -1;
// clicon_handle h = (clicon_handle)arg;
clicon_handle h = (clicon_handle)arg;
switch(ys->ys_keyword){
case Y_LEAF:
case Y_LEAF_LIST:
if (ys_populate_leaf(ys, NULL) < 0)
if (ys_populate_leaf(h, ys) < 0)
goto done;
break;
case Y_LIST:
if (ys_populate_list(ys, NULL) < 0)
if (ys_populate_list(h, ys) < 0)
goto done;
break;
case Y_RANGE:
if (ys_populate_range(ys, NULL) < 0)
if (ys_populate_range(h, ys) < 0)
goto done;
break;
case Y_LENGTH:
if (ys_populate_length(ys, NULL) < 0)
if (ys_populate_length(h, ys) < 0)
goto done;
break;
case Y_MANDATORY: /* call yang_mandatory() to check if set */
@ -1891,19 +1859,19 @@ ys_populate(yang_stmt *ys,
goto done;
break;
case Y_TYPE:
if (ys_populate_type(ys, NULL) < 0)
if (ys_populate_type(h, ys) < 0)
goto done;
break;
case Y_IDENTITY:
if (ys_populate_identity(ys, NULL) < 0)
if (ys_populate_identity(h, ys, NULL) < 0)
goto done;
break;
case Y_UNIQUE:
if (ys_populate_unique(ys) < 0)
if (ys_populate_unique(h, ys) < 0)
goto done;
break;
case Y_UNKNOWN:
if (ys_populate_unknown(ys) < 0)
if (ys_populate_unknown(h, ys) < 0)
goto done;
break;
default:
@ -2631,7 +2599,7 @@ yang_parse_post(clicon_handle h,
* Must be done using static binding.
*/
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;
/* 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_
LENGTH|RANGE. Can be a vector if multiple
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
YANG_OPTIONS_FRACTION_DIGITS */
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
*/
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 */
};

View file

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

View file

@ -32,6 +32,20 @@
***** END LICENSE BLOCK *****
* 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
@ -145,7 +159,8 @@ yang_type_cache_set(yang_type_cache **ycache0,
yang_stmt *resolved,
int options,
cvec *cvv,
char *pattern,
cvec *patterns,
cvec *regexps,
uint8_t fraction)
{
int retval = -1;
@ -166,8 +181,12 @@ yang_type_cache_set(yang_type_cache **ycache0,
goto done;
}
}
if (pattern && (ycache->yc_pattern = strdup(pattern)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
if (patterns && (ycache->yc_patterns = cvec_dup(patterns)) == NULL){
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;
}
ycache->yc_fraction = fraction;
@ -176,26 +195,42 @@ yang_type_cache_set(yang_type_cache **ycache0,
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
yang_type_cache_get(yang_type_cache *ycache,
yang_stmt **resolved,
int *options,
cvec **cvv,
char **pattern,
cvec *patterns,
cvec *regexps,
uint8_t *fraction)
{
int retval = -1;
cg_var *cv = NULL;
if (resolved)
*resolved = ycache->yc_resolved;
if (options)
*options = ycache->yc_options;
if (cvv)
*cvv = ycache->yc_cvv;
if (pattern)
*pattern = ycache->yc_pattern;
if (patterns){
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)
*fraction = ycache->yc_fraction;
return 0;
retval = 0;
// done:
return retval;
}
int
@ -205,15 +240,28 @@ yang_type_cache_cp(yang_type_cache **ycnew,
int retval = -1;
int options;
cvec *cvv;
char *pattern;
cvec *patterns = NULL;
cvec *regexps = NULL;
uint8_t fraction;
yang_stmt *resolved;
yang_type_cache_get(ycold, &resolved, &options, &cvv, &pattern, &fraction);
if (yang_type_cache_set(ycnew, resolved, options, cvv, pattern, fraction) < 0)
if ((patterns = cvec_new(0)) == NULL){
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;
retval = 0;
done:
if (patterns)
cvec_free(patterns);
if (regexps)
cvec_free(regexps);
return retval;
}
@ -222,12 +270,59 @@ yang_type_cache_free(yang_type_cache *ycache)
{
if (ycache->yc_cvv)
cvec_free(ycache->yc_cvv);
if (ycache->yc_pattern)
free(ycache->yc_pattern);
if (ycache->yc_patterns)
cvec_free(ycache->yc_patterns);
if (ycache->yc_regexps)
cvec_free(ycache->yc_regexps);
free(ycache);
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
* @param[in] ys This is a type statement
* @param[in] arg Not used
@ -238,28 +333,55 @@ int
ys_resolve_type(yang_stmt *ys,
void *arg)
{
clicon_handle h = (clicon_handle)arg;
int retval = -1;
int options = 0x0;
cvec *cvv = NULL;
char *pattern = NULL;
cvec *patterns = NULL;
cvec *regexps = NULL;
uint8_t fraction = 0;
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)
* 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,
&options, &cvv, &pattern, &fraction) < 0)
&options, &cvv, patterns, NULL, &fraction) < 0)
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,
resolved, options, cvv, pattern, fraction) < 0)
resolved, options, cvv,
patterns, regexps,
fraction) < 0)
goto done;
retval = 0;
done:
if (patterns)
cvec_free(patterns);
if (regexps)
cvec_free(regexps);
return retval;
}
@ -368,6 +490,48 @@ clicon_type2cv(char *origtype,
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 */
#define range_check(i, rmin, rmax, type) \
((rmin && (i) < cv_##type##_get(rmin)) || \
@ -375,9 +539,17 @@ clicon_type2cv(char *origtype,
/*! 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 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK
* @note reason if given must be freed by caller
*/
static int
cv_validate1(clicon_handle h,
@ -385,7 +557,7 @@ cv_validate1(clicon_handle h,
enum cv_type cvtype,
int options,
cvec *cvv,
char *pattern,
cvec *regexps,
yang_stmt *yrestype,
char *restype,
char **reason)
@ -554,29 +726,11 @@ cv_validate1(clicon_handle h,
}
}
}
if ((options & YANG_OPTIONS_PATTERN) != 0) {
void *re = NULL;
if ((re = yang_regex_cache_get(yrestype)) == NULL){
if ((ret = regex_compile(h, pattern, &re)) < 0)
if (regexps && cvec_len(regexps)) {
if ((ret = cv_validate_pattern(h, regexps, yrestype, str, reason)) < 0)
goto done;
if (ret == 0){
if (reason)
*reason = cligen_reason("regexp compile fail: \"%s\"",
pattern);
if (ret == 0)
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;
break;
}
}
break;
case CGV_VOID:
@ -605,6 +759,7 @@ static int ys_cv_validate_union(clicon_handle h,yang_stmt *ys, char **reason,
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 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK
@ -621,13 +776,17 @@ ys_cv_validate_union_one(clicon_handle h,
yang_stmt *yrt; /* union subtype */
int options = 0;
cvec *cvv = NULL;
char *pattern = NULL;
cvec *regexps = NULL;
uint8_t fraction = 0;
char *restype;
enum cv_type cvtype;
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)
goto done;
restype = yrt?yrt->ys_argument:NULL;
@ -650,16 +809,19 @@ ys_cv_validate_union_one(clicon_handle h,
if (retval == 0)
goto done;
if ((retval = cv_validate1(h, cvt, cvtype, options, cvv,
pattern, yrt, restype, reason)) < 0)
regexps, yrt, restype, reason)) < 0)
goto done;
}
done:
if (regexps)
cvec_free(regexps);
if (cvt)
cv_free(cvt);
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 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK
@ -705,14 +867,16 @@ ys_cv_validate_union(clicon_handle h,
/*! 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] 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
* describing the reason why the validation failed. Must be freed.
* @param[out] reason If given, and if return value is 0, contains malloced
* string describing reason why validation failed.
* @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
* See also cv_validate - the code is similar.
* @note reason if given must be freed by caller
*/
int
ys_cv_validate(clicon_handle h,
@ -724,7 +888,7 @@ ys_cv_validate(clicon_handle h,
cg_var *ycv; /* cv of yang-statement */
int options = 0;
cvec *cvv = NULL;
char *pattern = NULL;
cvec *regexps = NULL;
enum cv_type cvtype;
char *type; /* orig type */
yang_stmt *yrestype; /* resolved type */
@ -741,8 +905,14 @@ ys_cv_validate(clicon_handle h,
goto done;
}
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,
&options, &cvv, &pattern, &fraction) < 0)
&options, &cvv,
NULL, regexps,
&fraction) < 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
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 */
}
else
if ((retval = cv_validate1(h, cv, cvtype, options, cvv, pattern,
yrestype, restype, reason)) < 0)
if ((retval = cv_validate1(h, cv, cvtype, options, cvv,
regexps, yrestype, restype, reason)) < 0)
goto done;
done:
if (regexps)
cvec_free(regexps);
if (cvt)
cv_free(cvt);
return retval;
@ -876,45 +1048,63 @@ yang_find_identity(yang_stmt *ys,
return yid;
}
/*! Resolve type restrictions, return contraining parameters
* @param[in] yrange Yang type range restriction if any
* @param[in] ylength Yang type length restriction if any
* @param[in] ypattern Yang type pattern restriction if any
* @param[in] yfraction Yang type fraction restriction if any
/*! Resolve type restrictions, return constraining parameters
*
* This is for types with range/length/regexp restrictions of the base type
* Also fraction-digits for decimal64 is handled as that.
* @param[in] ytype yang-stmt object containing currently resolving type
* @param[out] options Pointer to flags field of optional values. optional
* @param[out] cvv Pointer to cvec with min range or 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
* @retval -1 Error
* @retval 0 OK.
*/
static int
resolve_restrictions(yang_stmt *yrange,
yang_stmt *ylength,
yang_stmt *ypattern,
yang_stmt *yfraction,
resolve_restrictions(yang_stmt *ytype,
int *options,
cvec **cvv,
char **pattern,
cvec *regexps,
uint8_t *fraction)
{
if (options && cvv && yrange != NULL){
*cvv = yrange->ys_cvec;
int retval = -1;
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;
}
if (options && cvv && ylength != NULL){
*cvv = ylength->ys_cvec;
if (options && cvv &&
(ys = yang_find(ytype, Y_LENGTH, NULL)) != NULL){
*cvv = ys->ys_cvec;
*options |= YANG_OPTIONS_LENGTH;
}
if (options && pattern && ypattern != NULL){
*pattern = ypattern->ys_argument;
*options |= YANG_OPTIONS_PATTERN;
/* Find all patterns */
if (options && regexps){
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;
}
if (options && fraction && yfraction != NULL){
*fraction = cv_uint8_get(yfraction->ys_cv);
pattern = ys->ys_argument; /* clear text pattern */
cv_string_set(cv, pattern);
}
}
if (options && fraction &&
(ys = yang_find(ytype, Y_FRACTION_DIGITS, NULL)) != NULL){
*fraction = cv_uint8_get(ys->ys_cv);
*options |= YANG_OPTIONS_FRACTION_DIGITS;
}
return 0;
retval = 0;
done:
return retval;
}
/*! 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.
* Present if options&YANG_OPTIONS_RANGE|_LENGTH.
* Can be a vector if multiple ranges
* @param[out] pattern String of POSIX regexp pattern
* Present if options&YANG_OPTIONS_PATTERN
* @param[out] patterns Initialized cvec of regexp patterns strings (if any)
* @param[out] regexps Initialized cvec of compiled regexps (if any)
* @param[out] fraction for decimal64, how many digits after period
* Present if options&YANG_OPTIONS_FRACTION_DIGITS
* @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:
* options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
* array of range_min, range_max cv:s
* options&YANG_OPTIONS_PATTERN --> pattern 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 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,
int *options,
cvec **cvv,
char **pattern,
cvec *patterns,
cvec *regexps,
uint8_t *fraction)
{
yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */
yang_stmt *rytype; /* Resolved type of ytype */
yang_stmt *yrange;
yang_stmt *ylength;
yang_stmt *ypattern;
yang_stmt *yfraction;
char *type;
char *prefix = NULL;
int retval = -1;
@ -968,23 +1155,18 @@ yang_type_resolve(yang_stmt *yorig,
type = yarg_id(ytype); /* This is the type to resolve */
prefix = yarg_prefix(ytype); /* And this its prefix */
/* 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,
options, cvv, pattern, fraction) < 0)
options, cvv, patterns, regexps, fraction) < 0)
goto done;
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 */
if (prefix == NULL && yang_builtin(type)){
if ((prefix == NULL && yang_builtin(type))){
*yrestype = ytype;
resolve_restrictions(yrange, ylength, ypattern, yfraction, options,
cvv, pattern, fraction);
if (resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0)
goto done;
goto ok;
}
@ -1023,11 +1205,13 @@ yang_type_resolve(yang_stmt *yorig,
}
/* recursively resolve this new type */
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;
/* overwrites the resolved if any */
resolve_restrictions(yrange, ylength, ypattern, yfraction, options,
cvv, pattern, fraction);
}
ok:
retval = 0;
@ -1043,17 +1227,17 @@ yang_type_resolve(yang_stmt *yorig,
* yang_stmt *yrestype;
* int options;
* cvec *cvv = NULL;
* char *pattern;
* cvec *patterns = cvec_new(0);
* cvec *regexps = cvec_new(0);
* 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;
* if (yrestype == NULL) # unresolved
* goto err;
* if (options & YANG_OPTIONS_LENGTH != 0)
* printf("%d..%d\n", min , max);
* if (options & YANG_OPTIONS_PATTERN != 0)
* printf("regexp: %s\n", pattern);
* @endcode
* @param[in] ys yang-stmt, leaf or leaf-list
* @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.
* Present if options&YANG_OPTIONS_RANGE|_LENGTH.
* Can be a vector if multiple ranges
* @param[out] pattern yang string pattern POSIX regexp patterns
* Present if options&YANG_OPTIONS_PATTERN
* @param[out] pattern yang cvec pattern POSIX regexp patterns
* @param[out] regexps Initialized cvec of compiled regexps (if any)
* @param[out] fraction for decimal64, how many digits after period
* Present if options&YANG_OPTIONS_FRACTION_DIGITS
* @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:
* options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
* array of range_min, range_max cv:s
* options&YANG_OPTIONS_PATTERN --> pattern 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 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,
int *options,
cvec **cvv,
char **pattern,
cvec *patterns,
cvec *regexps,
uint8_t *fraction
)
{
@ -1103,7 +1287,7 @@ yang_type_get(yang_stmt *ys,
if (origtype)
*origtype = type;
if (yang_type_resolve(ys, ys, ytype, yrestype,
options, cvv, pattern, fraction) < 0)
options, cvv, patterns, regexps, fraction) < 0)
goto done;
clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type,
*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
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"
#NOW=$(date +"%Y-%m-%dT%H:%M:%S")

View file

@ -200,7 +200,7 @@ EOF
# 1: dbcache true/false
testrun(){
dbcache=$1
new "test params: -f $cfg -y $fyang # dbcache: $dbcache"
new "test params: -f $cfg # dbcache: $dbcache"
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
@ -208,6 +208,7 @@ testrun(){
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</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_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -226,379 +227,379 @@ EOF
if [ $? -ne 0 ]; then
err
fi
new "start backend -s init -f $cfg -y $fyang"
start_backend -s init -f $cfg -y $fyang
new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting"
sleep $RCWAIT
fi
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"
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"
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"
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"
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"
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)"
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"
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)"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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
#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"
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"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 '^$'
expectfn "$clixon_cli -1f $cfg -l o validate" 0 '^$'
#-------- num0 empty 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"
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"
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)
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
#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"
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"
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"
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"
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
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"
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"
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"
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"
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"
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"
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"
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"
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"
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
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"
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"
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"
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"
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"
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
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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
# XXX how to enter negative numbers in bash string and cli -1?
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"
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"
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"
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"
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
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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---------------------
#-------- len1 single range (2)
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"
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"
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"
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"
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"
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
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"
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"
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
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
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"
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"
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"
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"
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
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"
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"
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"
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"
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"
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"
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"
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>]]>]]>$'
new "netconf pattern \w invalid"
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"
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
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"
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"
#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
new "Kill backend"

View file

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