From 6be0d112a6c5ff1d604b4b8192bd518a9af42686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Sch=C3=B6bel?= <jonathan@xn--schbel-yxa.info> Date: Wed, 6 Sep 2023 15:12:25 +0200 Subject: [PATCH] Validator: implemented allowed tag-attribute combinations The Validator can check if a attribute is allowed in a tag. It does so by associating allowed tags with attributes. This is done in that way, to support also attributes which are allowed for every tag (global attributes), but this is not yet supported. So some functions allow for NULL to be passed and some will still crash. The predicate SH_Validator_check_attr returns whether an attribute is allowed for a specific tag. If tag is NULL, it returns whether an attr is allowed at all, not whether it is allowed for every tag. For this another predicate will be provided, when this is to be implemented. The method SH_Validator_register_attr registers an tag-attr combination. Note, that it will automatically call SH_Validator_register_tag, if the tag doesn't exist. Later it will be possible, to set tag to NULL to register a global attribute, but for now the method will crash. The method SH_Validator_deregister_attr removes a tag-attr combination registered earlier. Note, that deregistering a non existent combination will result in an error. This behaviour is arguable and might be subject to change. When setting only tag to NULL, all tags for this attribute are deregistered. When setting only attr to NULL, all attrs for this tag are deregistered. This might suffer from problems, if this involves some attrs, that are global. Also this will use the internal method remove_tag_for_all_attrs, which has the problem, that it might fail partially. Normally when failing all functions revert the program to the same state, as it was before the call. This function however is different, as if it fails there might be some combinations, that haven't been removed, but others are already. Nevertheless, the validator is still in a valid state, so it is possible to call this function a second time, but it is not sure, which combinations are already deregistered. As the attrs also use the internal strings of the tags, it must be ensured, when a tag is deregistered, that all remaining references are removed, otherwise there would be dangling pointers. Note, that for this also remove_tag_for_all_attrs is used, so the method SH_Validator_deregister_tag suffers from the same problems listed above. Also if this internal method fails, the tag won't be removed at all. Furthermore, the tests for deregistering a tag are still missing. --- sefht.geany | 12 +- src/lib/sefht/validator_attr.c | 372 ++++++++++++++++++- src/lib/sefht/validator_attr.h | 5 +- src/lib/sefht/validator_attr_data.h | 7 + src/lib/sefht/validator_tag.c | 19 + tests/test_validator_attr.c | 534 +++++++++++++++++++++++++--- todo.txt | 5 + 7 files changed, 891 insertions(+), 63 deletions(-) diff --git a/sefht.geany b/sefht.geany index 4d6615e..5bbbe47 100644 --- a/sefht.geany +++ b/sefht.geany @@ -61,12 +61,12 @@ FILE_NAME_28=1867;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp FILE_NAME_29=3036;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8 FILE_NAME_30=1159;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8 FILE_NAME_31=1111;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_html.h;0;8 -FILE_NAME_32=5802;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8 +FILE_NAME_32=13741;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8 FILE_NAME_33=1148;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8 FILE_NAME_34=1124;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag_data.h;0;8 -FILE_NAME_35=1818;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.c;0;8 -FILE_NAME_36=1874;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.h;0;8 -FILE_NAME_37=1099;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr_data.h;0;8 +FILE_NAME_35=15732;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.c;0;8 +FILE_NAME_36=1682;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.h;0;8 +FILE_NAME_37=1111;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr_data.h;0;8 FILE_NAME_38=924;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8 FILE_NAME_39=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4 FILE_NAME_40=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8 @@ -83,8 +83,8 @@ FILE_NAME_50=4221;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp FILE_NAME_51=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_mark.c;0;8 FILE_NAME_52=2447;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8 FILE_NAME_53=3880;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_tag.c;0;8 -FILE_NAME_54=13518;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_attr.c;0;8 -FILE_NAME_55=536;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8 +FILE_NAME_54=29231;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_attr.c;0;8 +FILE_NAME_55=667;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8 FILE_NAME_56=201;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitlab-ci.yml;0;4 FILE_NAME_57=71;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Fupload.sh.in;0;8 FILE_NAME_58=806;Sh;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Frelease.sh.in;0;4 diff --git a/src/lib/sefht/validator_attr.c b/src/lib/sefht/validator_attr.c index d5f6218..5f42049 100644 --- a/src/lib/sefht/validator_attr.c +++ b/src/lib/sefht/validator_attr.c @@ -78,10 +78,18 @@ find_attr (const struct SH_Validator * validator, /*@out@*/ size_t * index) /*@modifies index@*/; +static inline +bool +find_attr_tag (const struct attr_info * attr, + /*@dependent@*/ const char * tag, + /*@out@*/ size_t * index) + /*@modifies index@*/; + static inline Attr add_attr (struct SH_Validator * validator, const char * attr, + /*@dependent@*/ const char * tag, size_t index, /*@null@*/ /*@out@*/ struct SH_Status * status) /*@modifies validator->attrs@*/ @@ -122,7 +130,7 @@ get_attr_id_by_name (struct SH_Validator * validator, static inline bool remove_attr (struct SH_Validator * validator, - const char * attr, + const size_t index, /*@null@*/ /*@out@*/ struct SH_Status * status) /*@modifies validator->attrs@*/ /*@modifies validator->attr_n@*/ @@ -132,6 +140,40 @@ remove_attr (struct SH_Validator * validator, /*@modifies status@*/; +static inline +bool +attr_add_tag (struct attr_info * attr, + const size_t index, + /*@dependent@*/ const char * tag, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +static inline +bool +attr_remove_tag (struct attr_info * attr, + const size_t index, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +static inline +bool +remove_tag_for_all_attrs (struct SH_Validator * validator, + /*@dependent@*/ const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status) + /*@modifies validator->attrs@*/ + /*@modifies validator->attr_n@*/ + /*@modifies validator->last_attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + static inline bool @@ -166,7 +208,9 @@ copy_attr (/*@special@*/ struct attr_info * copy, /*@modifies fileSystem@*/ /*@modifies status@*/ { + size_t index; char * name; + struct attr_tag_info * tags; name = strdup (attr->name); if (NULL == name) @@ -175,8 +219,22 @@ copy_attr (/*@special@*/ struct attr_info * copy, return FALSE; } + tags = malloc (sizeof (struct attr_tag_info) * attr->tag_n); + if (NULL == tags) + { + set_status (status, E_ALLOC, 3, "malloc failed"); + free (name); + return FALSE; + } + copy->id = attr->id; copy->name = name; + copy->tag_n = attr->tag_n; + copy->tags = tags; + for (index = 0; index < attr->tag_n; index++) + { + copy->tags[index] = attr->tags[index]; + } return TRUE; } @@ -234,6 +292,7 @@ free_attr (struct attr_info attr) /*@releases attr.name@*/ { free (attr.name); + free (attr.tags); return; } @@ -294,10 +353,49 @@ find_attr (const struct SH_Validator * validator, return FALSE; } +static inline +bool +find_attr_tag (const struct attr_info * attr, + /*@dependent@*/ const char * tag, + /*@out@*/ size_t * index) + /*@modifies index@*/ +{ + size_t start; + size_t end; + size_t pivot; + + start = 0; + end = attr->tag_n; + pivot = (end - start) / 2; + + while (start != end) + { + if (tag < attr->tags[pivot].name) + { + end = pivot; + pivot = (pivot - start) / 2 + start; + } + else if (tag == attr->tags[pivot].name) + { + *index = pivot; + return TRUE; + } + else + { + start = pivot + 1; + pivot = (end - pivot) / 2 + pivot; + } + } + + *index = start; + return FALSE; +} + static inline Attr add_attr (struct SH_Validator * validator, const char * attr, + /*@dependent@*/ const char * tag, size_t index, /*@null@*/ /*@out@*/ struct SH_Status * status) /*@modifies validator->attrs@*/ @@ -331,6 +429,17 @@ add_attr (struct SH_Validator * validator, return ATTR_ERR; } + attr_data.tags = malloc (sizeof (struct attr_tag_info)); + if (NULL == attr_data.tags) + { + set_status (status, E_ALLOC, 3, "malloc failed"); + free (attr_data.name); + return ATTR_ERR; + } + + attr_data.tags[0].name = tag; + attr_data.tag_n = 1; + /* allocate new space */ /* The addition and the multiplication is save, * because we have tested for this @@ -445,7 +554,7 @@ get_attr_id_by_name (struct SH_Validator * validator, static inline bool remove_attr (struct SH_Validator * validator, - const char * attr, + const size_t index, /*@null@*/ /*@out@*/ struct SH_Status * status) /*@modifies validator->attrs@*/ /*@modifies validator->attr_n@*/ @@ -456,16 +565,8 @@ remove_attr (struct SH_Validator * validator, { struct attr_info attr_data; struct attr_info * new_attrs; - size_t index; size_t index2; - if (!find_attr (validator, attr, &index)) - { - /* TODO: define whether this is an error */ - set_status (status, E_VALUE, 3, "no such attr"); - return FALSE; - } - /* preserve data as realloc may fail */ attr_data = validator->attrs[index]; @@ -502,16 +603,170 @@ remove_attr (struct SH_Validator * validator, return TRUE; } +static inline +bool +attr_add_tag (struct attr_info * attr, + const size_t index, + /*@dependent@*/ const char * tag, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct attr_tag_info * new_tags; + + if ((attr->tag_n == SIZE_MAX) + || ((attr->tag_n + 1) + > (SIZE_MAX / sizeof (struct attr_tag_info)))) + { + set_status (status, E_DOMAIN, 2, + "maximum number of tags per attr reached"); + return FALSE; + } + + new_tags = realloc (attr->tags, sizeof (struct attr_tag_info) + * (attr->tag_n + 1)); + if (NULL == new_tags) + { + set_status (status, E_ALLOC, 4, "realloc failed"); + return FALSE; + } + + for (size_t i = attr->tag_n; i > index; i--) + { + new_tags[i] = new_tags[i-1]; + } + new_tags[index].name = tag; + + attr->tags = new_tags; + attr->tag_n++; + + return TRUE; +} + +static inline +bool +attr_remove_tag (struct attr_info * attr, + const size_t index, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct attr_tag_info tag_data; + struct attr_tag_info * new_tags; + + /* preserve data as realloc may fail */ + tag_data = attr->tags[index]; + + for (size_t i = index; i < attr->tag_n-1; i++) + { + attr->tags[i] = attr->tags[i+1]; + } + + new_tags = realloc (attr->tags, sizeof (struct attr_tag_info) + * (attr->tag_n - 1)); + if (NULL == new_tags) + { + set_status (status, E_ALLOC, 4, "realloc failed"); + + for (size_t i = attr->tag_n; i > index; i--) + { + attr->tags[i] = attr->tags[i-1]; + } + attr->tags[index] = tag_data; + + return FALSE; + } + + attr->tags = new_tags; + attr->tag_n--; + + set_success (status); + return TRUE; +} + +static inline +bool +remove_tag_for_all_attrs (struct SH_Validator * validator, + /*@dependent@*/ const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status) + /*@modifies validator->attrs@*/ + /*@modifies validator->attr_n@*/ + /*@modifies validator->last_attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + /* note, that index is used for two different arrays */ + size_t index; + + for (index = 0; index < validator->attr_n; index++) + { + struct attr_info * attr; + attr = &validator->attrs[index]; + + if (1 == attr->tag_n) + { + if (tag == attr->tags[0].name) + { + if (!remove_attr (validator, index, + status)) + { + return FALSE; + } + } + } + else + { + size_t index; + if (find_attr_tag (attr, tag, &index)) + { + if (!attr_remove_tag (attr, index, + status)) + { + return FALSE; + } + } + } + } + + set_success (status); + return TRUE; +} + bool SH_Validator_check_attr (struct SH_Validator * validator, + /*@null@*/ const char * tag, const char * attr) /*@*/ { - return is_attr_name (validator, attr); + /* note, that index is used for three different arrays */ + size_t index; + + if (!find_attr (validator, attr, &index)) return FALSE; + + { + struct attr_info * attr; + attr = &validator->attrs[index]; + + if (NULL == tag) return TRUE; + + if (!find_tag (validator, tag, &index)) return FALSE; + tag = validator->tags[index].name; + + if (!find_attr_tag (attr, tag, &index)) return FALSE; + } + + return TRUE; } Attr SH_Validator_register_attr (struct SH_Validator * validator, + const char * tag, const char * attr, /*@null@*/ /*@out@*/ struct SH_Status * status) @@ -523,22 +778,41 @@ SH_Validator_register_attr (struct SH_Validator * validator, /*@modifies status@*/ { Attr attr_id; + /* note, that index is used for three different arrays */ size_t index; + if ((!find_tag (validator, tag, &index)) + && (!add_tag (validator, tag, index, status))) + { + return ATTR_ERR; + } + + tag = validator->tags[index].name; + /* attr already registered */ attr_id = get_attr_id_by_name (validator, attr, &index); if (attr_id != ATTR_ERR) { + struct attr_info * attr; + attr = &validator->attrs[index]; + + if ((!find_attr_tag (attr, tag, &index)) + && (!attr_add_tag (attr, index, tag, status))) + { + return ATTR_ERR; + } + set_success (status); return attr_id; } - return add_attr (validator, attr, index, status); + return add_attr (validator, attr, tag, index, status); } bool SH_Validator_deregister_attr (struct SH_Validator * validator, - const char * attr, + /*@null@*/ const char * tag, + /*@null@*/ const char * attr, /*@null@*/ /*@out@*/ struct SH_Status * status) /*@modifies validator->attr_n@*/ @@ -548,5 +822,75 @@ SH_Validator_deregister_attr (struct SH_Validator * validator, /*@modifies fileSystem@*/ /*@modifies status@*/ { - return remove_attr (validator, attr, status); + /* note, that index is used for three different arrays */ + size_t index; + + if ((NULL == tag) && (NULL == attr)) + { + free_attrs (validator); + init_attrs (validator); + set_success (status); + return TRUE; + } + + if (NULL == attr) + { + if (!find_tag (validator, tag, &index)) + { + /* TODO: define whether this is an error */ + set_status (status, E_VALUE, 3, "no such tag"); + return ATTR_ERR; + } + + tag = validator->tags[index].name; + return remove_tag_for_all_attrs (validator, tag, status); + } + + if (!find_attr (validator, attr, &index)) + { + /* TODO: define whether this is an error */ + set_status (status, E_VALUE, 3, "no such attr"); + return FALSE; + } + + { + struct attr_info * attr; + attr = &validator->attrs[index]; + + if (NULL == tag) + { + return remove_attr (validator, index, status); + } + + if (1 == attr->tag_n) + { + /* TODO: define whether this is an error */ + if (0 != strcmp (tag, attr->tags[0].name)) + { + set_status (status, E_VALUE, 2, + "no such tag"); + return ATTR_ERR; + } + + return remove_attr (validator, index, status); + } + + if (!find_tag (validator, tag, &index)) + { + /* TODO: define whether this is an error */ + set_status (status, E_VALUE, 3, "no such tag"); + return ATTR_ERR; + } + + tag = validator->tags[index].name; + + if (!find_attr_tag (attr, tag, &index)) + { + /* TODO: define whether this is an error */ + set_status (status, E_VALUE, 3, "no such tag"); + return FALSE; + } + + return attr_remove_tag (attr, index, status); + } } diff --git a/src/lib/sefht/validator_attr.h b/src/lib/sefht/validator_attr.h index 64ec2a5..e17e12a 100644 --- a/src/lib/sefht/validator_attr.h +++ b/src/lib/sefht/validator_attr.h @@ -43,6 +43,7 @@ typedef unsigned int Attr; Attr SH_Validator_register_attr (SH_Validator * validator, + const char * tag, const char * attr, /*@null@*/ /*@out@*/ struct SH_Status * status) @@ -53,7 +54,8 @@ SH_Validator_register_attr (SH_Validator * validator, bool SH_Validator_deregister_attr (SH_Validator * validator, - const char * attr, + /*@null@*/ const char * tag, + /*@null@*/ const char * attr, /*@null@*/ /*@out@*/ struct SH_Status * status) /*@modifies validator@*/ @@ -63,6 +65,7 @@ SH_Validator_deregister_attr (SH_Validator * validator, bool SH_Validator_check_attr (struct SH_Validator * validator, + /*@null@*/ const char * tag, const char * attr) /*@*/; diff --git a/src/lib/sefht/validator_attr_data.h b/src/lib/sefht/validator_attr_data.h index ff9d6cf..858a1b2 100644 --- a/src/lib/sefht/validator_attr_data.h +++ b/src/lib/sefht/validator_attr_data.h @@ -29,10 +29,17 @@ #error "Only <sefht/sefht.h> can be included directly." #endif +struct attr_tag_info +{ + /*@relnull@*/ /*@dependent@*/ const char * name; +}; + struct attr_info { Attr id; /*@only@*/ char * name; + size_t tag_n; + struct attr_tag_info * tags; }; #define NEXT_ATTR(attr) (attr + 1) diff --git a/src/lib/sefht/validator_tag.c b/src/lib/sefht/validator_tag.c index ab7f28e..9a24acf 100644 --- a/src/lib/sefht/validator_tag.c +++ b/src/lib/sefht/validator_tag.c @@ -562,6 +562,19 @@ get_tag_id_by_name (const struct SH_Validator * validator, return validator->tags[*index].id; } +static inline +bool +remove_tag_for_all_attrs (struct SH_Validator * validator, + /*@dependent@*/ const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status) + /*@modifies validator->attrs@*/ + /*@modifies validator->attr_n@*/ + /*@modifies validator->last_attr@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + static inline bool remove_tag (struct SH_Validator * validator, Tag id, @@ -587,6 +600,12 @@ remove_tag (struct SH_Validator * validator, Tag id, /* don't free name yet, as realloc may fail */ name = tags[index].name; + /* clear all references of this tag */ + if (!remove_tag_for_all_attrs (validator, name, status)) + { + return FALSE; + } + for (index2 = index; index2 < tag_n-1; index2++) { tags[index2] = tags[index2+1]; diff --git a/tests/test_validator_attr.c b/tests/test_validator_attr.c index fdf49b4..f6cb44a 100644 --- a/tests/test_validator_attr.c +++ b/tests/test_validator_attr.c @@ -83,10 +83,10 @@ START_TEST(test_validator_copy_no_status) validator = SH_Validator_new_html5 (NULL); ck_assert_ptr_ne (NULL, validator); - attr = SH_Validator_register_attr (validator, "id", NULL); + attr = SH_Validator_register_attr (validator, "body", "id", NULL); ck_assert_int_ne (ATTR_ERR, attr); - attr = SH_Validator_register_attr (validator, "lang", NULL); + attr = SH_Validator_register_attr (validator, "html", "lang", NULL); ck_assert_int_ne (ATTR_ERR, attr); /* test */ @@ -99,6 +99,7 @@ START_TEST(test_validator_copy_no_status) ck_assert_int_eq (validator->last_attr, copy->last_attr); #define TEST_INT(I) ck_assert_int_eq (validator->I, copy->I); + #define TEST_PTR(P) ck_assert_ptr_eq (validator->P, copy->P); #define TEST_STR(S) ck_assert_ptr_ne (validator->S, copy->S); \ ck_assert_str_eq (validator->S, copy->S); @@ -106,8 +107,15 @@ START_TEST(test_validator_copy_no_status) { TEST_INT(attrs[index].id) TEST_STR(attrs[index].name) + + TEST_INT(attrs[index].tag_n) + for (size_t j = 0; j < copy->attrs[index].tag_n; j++) + { + TEST_PTR(attrs[index].tags[j].name) + } } #undef TEST_INT + #undef TEST_PTR #undef TEST_STR SH_Validator_free (copy); @@ -126,10 +134,10 @@ START_TEST(test_validator_copy_with_status) validator = SH_Validator_new_html5 (NULL); ck_assert_ptr_ne (NULL, validator); - attr = SH_Validator_register_attr (validator, "id", NULL); + attr = SH_Validator_register_attr (validator, "body", "id", NULL); ck_assert_int_ne (ATTR_ERR, attr); - attr = SH_Validator_register_attr (validator, "lang", NULL); + attr = SH_Validator_register_attr (validator, "html", "lang", NULL); ck_assert_int_ne (ATTR_ERR, attr); /* test */ @@ -144,6 +152,7 @@ START_TEST(test_validator_copy_with_status) ck_assert_int_eq (validator->last_attr, copy->last_attr); #define TEST_INT(I) ck_assert_int_eq (validator->I, copy->I); + #define TEST_PTR(P) ck_assert_ptr_eq (validator->P, copy->P); #define TEST_STR(S) ck_assert_ptr_ne (validator->S, copy->S); \ ck_assert_str_eq (validator->S, copy->S); @@ -151,8 +160,15 @@ START_TEST(test_validator_copy_with_status) { TEST_INT(attrs[index].id) TEST_STR(attrs[index].name) + + TEST_INT(attrs[index].tag_n) + for (size_t j = 0; j < copy->attrs[index].tag_n; j++) + { + TEST_PTR(attrs[index].tags[j].name) + } } #undef TEST_INT + #undef TEST_PTR #undef TEST_STR SH_Validator_free (copy); @@ -163,6 +179,11 @@ END_TEST START_TEST(test_validator_register_no_status) { struct SH_Validator * validator; + const char * tag1 = "html"; + const char * tag2 = "foobarbaz"; // mustn't be registered yet + const char * tag3 = "body"; + const char * tag4 = "nav"; + const char * tag5 = "aside"; const char * attr1 = "id"; const char * attr2 = "class"; const char * attr3 = "name"; @@ -177,33 +198,73 @@ START_TEST(test_validator_register_no_status) ck_assert_ptr_ne (NULL, validator); /* test - register */ - attr = SH_Validator_register_attr (validator, attr1, NULL); + attr = SH_Validator_register_attr (validator, tag1, attr1, NULL); ck_assert_int_eq (1, attr); ck_assert_int_eq (validator->attr_n, 1); ck_assert_int_eq (validator->last_attr, attr); ck_assert_int_eq (validator->attrs[0].id, attr); + ck_assert_ptr_ne (validator->attrs[0].name, attr1); ck_assert_str_eq (validator->attrs[0].name, attr1); + ck_assert_int_eq (validator->attrs[0].tag_n, 1); + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag1); + /* test - duplicate registration */ - attr_ = SH_Validator_register_attr (validator, attr1, NULL); + attr_ = SH_Validator_register_attr (validator, tag1, attr1, NULL); ck_assert_int_eq (attr_, attr); ck_assert_int_eq (validator->attr_n, 1); ck_assert_int_eq (validator->last_attr, attr); + ck_assert_int_eq (validator->attrs[0].id, attr); + ck_assert_ptr_ne (validator->attrs[0].name, attr1); + ck_assert_str_eq (validator->attrs[0].name, attr1); + + ck_assert_int_eq (validator->attrs[0].tag_n, 1); + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag1); + + /* test - automatic tag register */ + attr = SH_Validator_register_attr (validator, tag2, attr1, NULL); + ck_assert_int_eq (1, attr); + + ck_assert_int_eq (validator->attr_n, 1); + ck_assert_int_eq (validator->last_attr, attr); + ck_assert_int_eq (validator->attrs[0].id, attr); ck_assert_str_eq (validator->attrs[0].name, attr1); - /* test - order */ - attr = SH_Validator_register_attr (validator, attr3, NULL); + ck_assert_int_eq (validator->attrs[0].tag_n, 2); + /* The storage order depends on the relative position of memory, + * allocated by different malloc calls. This can change and + * thus must be determined. */ + if (validator->attrs[0].tags[0].name[0] + > validator->attrs[0].tags[1].name[0]) + { + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag1); + ck_assert_ptr_ne (validator->attrs[0].tags[1].name, tag2); + ck_assert_str_eq (validator->attrs[0].tags[1].name, tag2); + } + else + { + ck_assert_ptr_ne (validator->attrs[0].tags[1].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[1].name, tag1); + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag2); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag2); + } + + /* test - order (attr) */ + attr = SH_Validator_register_attr (validator, tag1, attr3, NULL); ck_assert_int_eq (attr, 2); - attr = SH_Validator_register_attr (validator, attr4, NULL); + attr = SH_Validator_register_attr (validator, tag1, attr4, NULL); ck_assert_int_eq (attr, 3); - attr = SH_Validator_register_attr (validator, attr5, NULL); + attr = SH_Validator_register_attr (validator, tag1, attr5, NULL); ck_assert_int_eq (attr, 4); ck_assert_int_eq (validator->attr_n, 4); @@ -213,6 +274,27 @@ START_TEST(test_validator_register_no_status) ck_assert_str_eq (validator->attrs[2].name, attr3); ck_assert_str_eq (validator->attrs[3].name, attr4); + /* test - order (tag) */ + attr = SH_Validator_register_attr (validator, tag2, attr4, NULL); + ck_assert_int_eq (attr, 3); + + attr = SH_Validator_register_attr (validator, tag3, attr4, NULL); + ck_assert_int_eq (attr, 3); + + attr = SH_Validator_register_attr (validator, tag4, attr4, NULL); + ck_assert_int_eq (attr, 3); + + attr = SH_Validator_register_attr (validator, tag5, attr4, NULL); + ck_assert_int_eq (attr, 3); + + ck_assert_int_eq (5, validator->attrs[3].tag_n); + + for (size_t i = 0; i < validator->attrs[3].tag_n-1; i++) + { + ck_assert_int_lt ((size_t)validator->attrs[3].tags[i].name, + (size_t)validator->attrs[3].tags[i+1].name); + } + /* test - overflow detection */ /* make method fail by filling with garbage until * upper boundary is reached */ @@ -230,12 +312,12 @@ START_TEST(test_validator_register_no_status) { sprintf (attrN, "attr%zu", validator->attr_n); } - while (ATTR_ERR != SH_Validator_register_attr (validator, attrN, NULL)); + while (ATTR_ERR != SH_Validator_register_attr (validator, tag1, attrN, NULL)); free (attrN); /* test overflow #1 */ - attr = SH_Validator_register_attr (validator, attr2, NULL); + attr = SH_Validator_register_attr (validator, tag1, attr2, NULL); ck_assert_int_eq (ATTR_ERR, attr); ck_assert_int_eq (validator->attr_n, 10); @@ -244,7 +326,7 @@ START_TEST(test_validator_register_no_status) validator->attr_n = 1; validator->last_attr = ATTR_MAX; - attr = SH_Validator_register_attr (validator, attr2, NULL); + attr = SH_Validator_register_attr (validator, tag1, attr2, NULL); ck_assert_int_eq (ATTR_ERR, attr); ck_assert_int_eq (validator->attr_n, 1); @@ -260,6 +342,11 @@ START_TEST(test_validator_register_with_status) { struct SH_Status status; struct SH_Validator * validator; + const char * tag1 = "html"; + const char * tag2 = "foobarbaz"; // mustn't be registered yet + const char * tag3 = "body"; + const char * tag4 = "nav"; + const char * tag5 = "aside"; const char * attr1 = "id"; const char * attr2 = "class"; const char * attr3 = "name"; @@ -275,7 +362,7 @@ START_TEST(test_validator_register_with_status) /* test - register */ _status_preinit (status); - attr = SH_Validator_register_attr (validator, attr1, &status); + attr = SH_Validator_register_attr (validator, tag1, attr1, &status); ck_assert_int_eq (1, attr); ck_assert_int_eq (SUCCESS, status.status); @@ -283,33 +370,75 @@ START_TEST(test_validator_register_with_status) ck_assert_int_eq (validator->last_attr, attr); ck_assert_int_eq (validator->attrs[0].id, attr); + ck_assert_ptr_ne (validator->attrs[0].name, attr1); ck_assert_str_eq (validator->attrs[0].name, attr1); + ck_assert_int_eq (validator->attrs[0].tag_n, 1); + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag1); + /* test - duplicate registration */ _status_preinit (status); - attr_ = SH_Validator_register_attr (validator, attr1, &status); + attr_ = SH_Validator_register_attr (validator, tag1, attr1, &status); ck_assert_int_eq (attr_, attr); ck_assert_int_eq (SUCCESS, status.status); ck_assert_int_eq (validator->attr_n, 1); ck_assert_int_eq (validator->last_attr, attr); + ck_assert_int_eq (validator->attrs[0].id, attr); + ck_assert_ptr_ne (validator->attrs[0].name, attr1); + ck_assert_str_eq (validator->attrs[0].name, attr1); + + ck_assert_int_eq (validator->attrs[0].tag_n, 1); + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag1); + + /* test - automatic tag register */ + _status_preinit (status); + attr = SH_Validator_register_attr (validator, tag2, attr1, &status); + ck_assert_int_eq (1, attr); + ck_assert_int_eq (SUCCESS, status.status); + + ck_assert_int_eq (validator->attr_n, 1); + ck_assert_int_eq (validator->last_attr, attr); + ck_assert_int_eq (validator->attrs[0].id, attr); ck_assert_str_eq (validator->attrs[0].name, attr1); - /* test - order */ + ck_assert_int_eq (validator->attrs[0].tag_n, 2); + /* The storage order depends on the relative position of memory, + * allocated by different malloc calls. This can change and + * thus must be determined. */ + if (validator->attrs[0].tags[0].name[0] + > validator->attrs[0].tags[1].name[0]) + { + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag1); + ck_assert_ptr_ne (validator->attrs[0].tags[1].name, tag2); + ck_assert_str_eq (validator->attrs[0].tags[1].name, tag2); + } + else + { + ck_assert_ptr_ne (validator->attrs[0].tags[1].name, tag1); + ck_assert_str_eq (validator->attrs[0].tags[1].name, tag1); + ck_assert_ptr_ne (validator->attrs[0].tags[0].name, tag2); + ck_assert_str_eq (validator->attrs[0].tags[0].name, tag2); + } + + /* test - order (attr) */ _status_preinit (status); - attr = SH_Validator_register_attr (validator, attr3, &status); + attr = SH_Validator_register_attr (validator, tag1, attr3, &status); ck_assert_int_eq (attr, 2); ck_assert_int_eq (status.status, SUCCESS); _status_preinit (status); - attr = SH_Validator_register_attr (validator, attr4, &status); + attr = SH_Validator_register_attr (validator, tag1, attr4, &status); ck_assert_int_eq (attr, 3); ck_assert_int_eq (status.status, SUCCESS); _status_preinit (status); - attr = SH_Validator_register_attr (validator, attr5, &status); + attr = SH_Validator_register_attr (validator, tag1, attr5, &status); ck_assert_int_eq (attr, 4); ck_assert_int_eq (status.status, SUCCESS); @@ -320,6 +449,35 @@ START_TEST(test_validator_register_with_status) ck_assert_str_eq (validator->attrs[2].name, attr3); ck_assert_str_eq (validator->attrs[3].name, attr4); + /* test - order (tag) */ + _status_preinit (status); + attr = SH_Validator_register_attr (validator, tag2, attr4, &status); + ck_assert_int_eq (attr, 3); + ck_assert_int_eq (status.status, SUCCESS); + + _status_preinit (status); + attr = SH_Validator_register_attr (validator, tag3, attr4, &status); + ck_assert_int_eq (attr, 3); + ck_assert_int_eq (status.status, SUCCESS); + + _status_preinit (status); + attr = SH_Validator_register_attr (validator, tag4, attr4, &status); + ck_assert_int_eq (attr, 3); + ck_assert_int_eq (status.status, SUCCESS); + + _status_preinit (status); + attr = SH_Validator_register_attr (validator, tag5, attr4, &status); + ck_assert_int_eq (attr, 3); + ck_assert_int_eq (status.status, SUCCESS); + + ck_assert_int_eq (5, validator->attrs[3].tag_n); + + for (size_t i = 0; i < validator->attrs[3].tag_n-1; i++) + { + ck_assert_int_lt ((size_t)validator->attrs[3].tags[i].name, + (size_t)validator->attrs[3].tags[i+1].name); + } + /* test - overflow detection */ /* make method fail by filling with garbage until * upper boundary is reached */ @@ -337,13 +495,13 @@ START_TEST(test_validator_register_with_status) { sprintf (attrN, "attr%zu", validator->attr_n); } - while (ATTR_ERR != SH_Validator_register_attr (validator, attrN, NULL)); + while (ATTR_ERR != SH_Validator_register_attr (validator, tag1, attrN, NULL)); free (attrN); /* test overflow #1 */ _status_preinit (status); - attr = SH_Validator_register_attr (validator, attr2, &status); + attr = SH_Validator_register_attr (validator, tag1, attr2, &status); ck_assert_int_eq (ATTR_ERR, attr); ck_assert_int_eq (E_DOMAIN, status.status); @@ -354,7 +512,7 @@ START_TEST(test_validator_register_with_status) validator->last_attr = ATTR_MAX; _status_preinit (status); - attr = SH_Validator_register_attr (validator, attr2, &status); + attr = SH_Validator_register_attr (validator, tag1, attr2, &status); ck_assert_int_eq (ATTR_ERR, attr); ck_assert_int_eq (E_DOMAIN, status.status); @@ -377,27 +535,156 @@ START_TEST(test_validator_deregister_no_status) validator = SH_Validator_new (NULL); ck_assert_ptr_ne (NULL, validator); - attr = SH_Validator_register_attr (validator, "attr", NULL); + attr = SH_Validator_register_attr (validator, "html", "attr", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "html", "id", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "html", "name", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "html", "class", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "attr", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "id", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "name", NULL); ck_assert_int_ne (ATTR_ERR, attr); - attr = SH_Validator_register_attr (validator, "id", NULL); + attr = SH_Validator_register_attr (validator, "body", "class", NULL); ck_assert_int_ne (ATTR_ERR, attr); /* test - consistency */ - ck_assert_int_eq (2, validator->attr_n); + ck_assert_int_eq (4, validator->attr_n); ck_assert_str_eq ("attr", validator->attrs[0].name); - ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_str_eq ("class", validator->attrs[1].name); + ck_assert_str_eq ("id", validator->attrs[2].name); + ck_assert_str_eq ("name", validator->attrs[3].name); + ck_assert_int_eq (2, validator->attrs[0].tag_n); + ck_assert_int_eq (2, validator->attrs[1].tag_n); + ck_assert_int_eq (2, validator->attrs[2].tag_n); + ck_assert_int_eq (2, validator->attrs[3].tag_n); + + /* The storage order depends on the relative position of memory, + * allocated by different malloc calls. This can change and + * thus must be determined. */ + if (validator->attrs[0].tags[0].name[0] + > validator->attrs[0].tags[1].name[0]) + { + ck_assert_str_eq ("html", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[2].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[3].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[2].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[3].tags[1].name); + } + else + { + ck_assert_str_eq ("html", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[2].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[3].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[2].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[3].tags[0].name); + } + /* test - existent attr */ - result = SH_Validator_deregister_attr (validator, "attr", NULL); + result = SH_Validator_deregister_attr (validator, "html", "attr", + NULL); + ck_assert_int_eq (TRUE, result); + + /* test - non existent tag */ + result = SH_Validator_deregister_attr (validator, "html", "attr", + NULL); + ck_assert_int_eq (FALSE, result); + + /* test - existent attr, auto remove */ + result = SH_Validator_deregister_attr (validator, "body", "attr", + NULL); ck_assert_int_eq (TRUE, result); + /* test - consistency */ + ck_assert_int_eq (3, validator->attr_n); + ck_assert_str_eq ("class", validator->attrs[0].name); + ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_str_eq ("name", validator->attrs[2].name); + ck_assert_int_eq (2, validator->attrs[0].tag_n); + ck_assert_int_eq (2, validator->attrs[1].tag_n); + ck_assert_int_eq (2, validator->attrs[2].tag_n); + + /* test - non existent attr */ - result = SH_Validator_deregister_attr (validator, "attr", NULL); + result = SH_Validator_deregister_attr (validator, "html", "attr", + NULL); + ck_assert_int_eq (FALSE, result); + + /* test - existent attr, total remove */ + result = SH_Validator_deregister_attr (validator, NULL, "name", + NULL); + ck_assert_int_eq (TRUE, result); + + /* test - non existent attr, total remove */ + result = SH_Validator_deregister_attr (validator, NULL, "attr", + NULL); ck_assert_int_eq (FALSE, result); /* test - consistency */ - ck_assert_int_eq (1, validator->attr_n); - ck_assert_str_eq ("id", validator->attrs[0].name); + ck_assert_int_eq (2, validator->attr_n); + ck_assert_str_eq ("class", validator->attrs[0].name); + ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_int_eq (2, validator->attrs[0].tag_n); + ck_assert_int_eq (2, validator->attrs[1].tag_n); + + /* The storage order depends on the relative position of memory, + * allocated by different malloc calls. This can change and + * thus must be determined. */ + if (validator->attrs[0].tags[0].name[0] + > validator->attrs[0].tags[1].name[0]) + { + ck_assert_str_eq ("html", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[1].name); + } + else + { + ck_assert_str_eq ("html", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[0].name); + } + + + /* test - existent tag, total remove */ + result = SH_Validator_deregister_attr (validator, "html", NULL, + NULL); + ck_assert_int_eq (TRUE, result); + + /* test - non existent tag, total remove */ + result = SH_Validator_deregister_attr (validator, "nav", NULL, + NULL); + ck_assert_int_eq (FALSE, result); + + /* test - consistency */ + ck_assert_int_eq (2, validator->attr_n); + ck_assert_str_eq ("class", validator->attrs[0].name); + ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_int_eq (1, validator->attrs[0].tag_n); + ck_assert_int_eq (1, validator->attrs[1].tag_n); + ck_assert_str_eq ("body", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[0].name); + + /* test - total clear */ + result = SH_Validator_deregister_attr (validator, NULL, NULL, + NULL); + ck_assert_int_eq (TRUE, result); + + /* test - consistency */ + ck_assert_int_eq (0, validator->attr_n); + /* cleanup */ SH_Validator_free (validator); @@ -415,33 +702,174 @@ START_TEST(test_validator_deregister_with_status) validator = SH_Validator_new (NULL); ck_assert_ptr_ne (NULL, validator); - attr = SH_Validator_register_attr (validator, "attr", NULL); + attr = SH_Validator_register_attr (validator, "html", "attr", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "html", "id", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "html", "name", NULL); ck_assert_int_ne (ATTR_ERR, attr); - attr = SH_Validator_register_attr (validator, "id", NULL); + attr = SH_Validator_register_attr (validator, "html", "class", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "attr", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "id", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "name", NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, "body", "class", NULL); ck_assert_int_ne (ATTR_ERR, attr); /* test - consistency */ - ck_assert_int_eq (2, validator->attr_n); + ck_assert_int_eq (4, validator->attr_n); ck_assert_str_eq ("attr", validator->attrs[0].name); - ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_str_eq ("class", validator->attrs[1].name); + ck_assert_str_eq ("id", validator->attrs[2].name); + ck_assert_str_eq ("name", validator->attrs[3].name); + ck_assert_int_eq (2, validator->attrs[0].tag_n); + ck_assert_int_eq (2, validator->attrs[1].tag_n); + ck_assert_int_eq (2, validator->attrs[2].tag_n); + ck_assert_int_eq (2, validator->attrs[3].tag_n); + + /* The storage order depends on the relative position of memory, + * allocated by different malloc calls. This can change and + * thus must be determined. */ + if (validator->attrs[0].tags[0].name[0] + > validator->attrs[0].tags[1].name[0]) + { + ck_assert_str_eq ("html", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[2].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[3].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[2].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[3].tags[1].name); + } + else + { + ck_assert_str_eq ("html", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[2].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[3].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[2].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[3].tags[0].name); + } + /* test - existent attr */ _status_preinit (status); - result = SH_Validator_deregister_attr (validator, "attr", + result = SH_Validator_deregister_attr (validator, "html", "attr", &status); ck_assert_int_eq (TRUE, result); ck_assert_int_eq (SUCCESS, status.status); + /* test - non existent tag */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, "html", "attr", + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_VALUE, status.status); + + /* test - existent attr, auto remove */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, "body", "attr", + &status); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (SUCCESS, status.status); + + /* test - consistency */ + ck_assert_int_eq (3, validator->attr_n); + ck_assert_str_eq ("class", validator->attrs[0].name); + ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_str_eq ("name", validator->attrs[2].name); + ck_assert_int_eq (2, validator->attrs[0].tag_n); + ck_assert_int_eq (2, validator->attrs[1].tag_n); + ck_assert_int_eq (2, validator->attrs[2].tag_n); + + /* test - non existent attr */ _status_preinit (status); - result = SH_Validator_deregister_attr (validator, "attr", + result = SH_Validator_deregister_attr (validator, "html", "attr", + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_VALUE, status.status); + + /* test - existent attr, total remove */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, NULL, "name", + &status); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (SUCCESS, status.status); + + /* test - non existent attr, total remove */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, NULL, "attr", &status); ck_assert_int_eq (FALSE, result); ck_assert_int_eq (E_VALUE, status.status); /* test - consistency */ - ck_assert_int_eq (1, validator->attr_n); - ck_assert_str_eq ("id", validator->attrs[0].name); + ck_assert_int_eq (2, validator->attr_n); + ck_assert_str_eq ("class", validator->attrs[0].name); + ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_int_eq (2, validator->attrs[0].tag_n); + ck_assert_int_eq (2, validator->attrs[1].tag_n); + + /* The storage order depends on the relative position of memory, + * allocated by different malloc calls. This can change and + * thus must be determined. */ + if (validator->attrs[0].tags[0].name[0] + > validator->attrs[0].tags[1].name[0]) + { + ck_assert_str_eq ("html", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[1].name); + } + else + { + ck_assert_str_eq ("html", validator->attrs[0].tags[1].name); + ck_assert_str_eq ("html", validator->attrs[1].tags[1].name); + ck_assert_str_eq ("body", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[0].name); + } + + + /* test - existent tag, total remove */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, "html", NULL, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (SUCCESS, status.status); + + /* test - non existent tag, total remove */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, "nav", NULL, + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_VALUE, status.status); + + /* test - consistency */ + ck_assert_int_eq (2, validator->attr_n); + ck_assert_str_eq ("class", validator->attrs[0].name); + ck_assert_str_eq ("id", validator->attrs[1].name); + ck_assert_int_eq (1, validator->attrs[0].tag_n); + ck_assert_int_eq (1, validator->attrs[1].tag_n); + ck_assert_str_eq ("body", validator->attrs[0].tags[0].name); + ck_assert_str_eq ("body", validator->attrs[1].tags[0].name); + + /* test - total clear */ + _status_preinit (status); + result = SH_Validator_deregister_attr (validator, NULL, NULL, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (SUCCESS, status.status); + + /* test - consistency */ + ck_assert_int_eq (0, validator->attr_n); + /* cleanup */ SH_Validator_free (validator); @@ -451,9 +879,14 @@ END_TEST START_TEST(test_validator_check) { struct SH_Validator * validator; + const char * tag1 = "html"; + const char * tag2 = "html"; + const char * tag3 = "head"; + const char * tag4 = "body"; const char * attr1 = "id"; const char * attr2 = "id"; const char * attr3 = "class"; + const char * attr4 = "name"; Tag attr; bool result; @@ -461,17 +894,34 @@ START_TEST(test_validator_check) validator = SH_Validator_new (NULL); ck_assert_ptr_ne (NULL, validator); - attr = SH_Validator_register_attr (validator, attr1, NULL); + attr = SH_Validator_register_attr (validator, tag1, attr1, NULL); + ck_assert_int_ne (ATTR_ERR, attr); + attr = SH_Validator_register_attr (validator, tag3, attr3, NULL); ck_assert_int_ne (ATTR_ERR, attr); /* test */ - result = SH_Validator_check_attr (validator, attr1); + result = SH_Validator_check_attr (validator, tag1, attr1); + ck_assert_int_eq (TRUE, result); + + result = SH_Validator_check_attr (validator, tag2, attr2); ck_assert_int_eq (TRUE, result); - result = SH_Validator_check_attr (validator, attr2); + result = SH_Validator_check_attr (validator, tag1, attr3); + ck_assert_int_eq (FALSE, result); + + result = SH_Validator_check_attr (validator, tag3, attr4); + ck_assert_int_eq (FALSE, result); + + result = SH_Validator_check_attr (validator, tag4, attr2); + ck_assert_int_eq (FALSE, result); + + result = SH_Validator_check_attr (validator, tag4, attr4); + ck_assert_int_eq (FALSE, result); + + result = SH_Validator_check_attr (validator, NULL, attr2); ck_assert_int_eq (TRUE, result); - result = SH_Validator_check_attr (validator, attr3); + result = SH_Validator_check_attr (validator, NULL, attr4); ck_assert_int_eq (FALSE, result); /* cleanup */ diff --git a/todo.txt b/todo.txt index 0de5b07..3c9b4df 100644 --- a/todo.txt +++ b/todo.txt @@ -20,3 +20,8 @@ Fragment: - support of newlines (72/79/80) - support of escaping html symbols (but only which are special in context) - support for mapping special chars -> html entities + +Validator: +- bugfix: remove_attr: failure recovery, fix move back loop +- remove unnecessary ids +- tests missing for deregister_tag -- GitLab