From 945559d35ba0943d392869baed3ae1a066f13ffe Mon Sep 17 00:00:00 2001 From: Ken Murchison Date: Wed, 24 Apr 2024 10:56:45 -0400 Subject: [PATCH] fix vcardrestriction_check() and regression tests --- src/libicalvcard/vcardrestriction.c.in | 32 +++--- src/test/libicalvcard/vcard_test.c | 152 +++++++++++++++++++++---- test-data/test.vcf | 2 +- 3 files changed, 143 insertions(+), 43 deletions(-) diff --git a/src/libicalvcard/vcardrestriction.c.in b/src/libicalvcard/vcardrestriction.c.in index 760c707f9..d188957e6 100644 --- a/src/libicalvcard/vcardrestriction.c.in +++ b/src/libicalvcard/vcardrestriction.c.in @@ -103,7 +103,7 @@ static int _check_restriction(vcardcomponent *comp, if (restr == VCARD_RESTRICTION_ONEEXCLUSIVE || restr == VCARD_RESTRICTION_ONEMUTUAL) { - /* First treat is as a 0/1 restriction */ + /* First treat it as a 0/1 restriction */ restr = VCARD_RESTRICTION_ZEROORONE; } @@ -157,10 +157,10 @@ static int _check_restriction(vcardcomponent *comp, return compare; } -static int vcardrestriction_check_component(vcardproperty_version version, - vcardcomponent *comp) +static int vcardrestriction_check_component(vcardcomponent *comp) { vcardcomponent_kind comp_kind, inner_kind; + vcardproperty_version version; vcardproperty_kind prop_kind; const vcardrestriction_record *start_record; vcardproperty *version_prop = NULL; @@ -204,10 +204,10 @@ static int vcardrestriction_check_component(vcardproperty_version version, /* Check all of the properties in this component */ - start_record = vcardrestriction_get_restriction(NULL, version, comp_kind, - VCARD_ANY_PROPERTY, - VCARD_NO_COMPONENT); - + start_record = vcardrestriction_get_restriction(NULL, VCARD_VERSION_NONE, + comp_kind, + VCARD_ANY_PROPERTY, + VCARD_NO_COMPONENT); if (start_record != &null_restriction_record) { for (prop_kind = VCARD_ANY_PROPERTY + 1; @@ -227,14 +227,11 @@ static int vcardrestriction_check_component(vcardproperty_version version, valid = valid && compare; } } - else { - start_record = NULL; - } /* Now check the inner components */ - start_record = vcardrestriction_get_restriction(start_record, - version, comp_kind, + start_record = vcardrestriction_get_restriction(NULL, VCARD_VERSION_NONE, + comp_kind, VCARD_NO_PROPERTY, VCARD_ANY_COMPONENT); @@ -259,7 +256,7 @@ static int vcardrestriction_check_component(vcardproperty_version version, inner_comp != 0; inner_comp = vcardcomponent_get_next_component(comp, VCARD_ANY_COMPONENT)) { - compare = vcardrestriction_check_component(version, inner_comp); + compare = vcardrestriction_check_component(inner_comp); valid = valid && compare; } @@ -276,13 +273,13 @@ int vcardrestriction_check(vcardcomponent *outer_comp) comp_kind = vcardcomponent_isa(outer_comp); - if (comp_kind != VCARD_VCARD_COMPONENT && comp_kind != VCARD_XROOT_COMPONENT) { + if (comp_kind != VCARD_VCARD_COMPONENT && + comp_kind != VCARD_XROOT_COMPONENT) { icalerror_set_errno(ICAL_BADARG_ERROR); return 0; } - /* Check the VCALENDAR wrapper */ - valid = vcardrestriction_check_component(VCARD_VERSION_NONE, outer_comp); + valid = vcardrestriction_check_component(outer_comp); return valid; } @@ -302,7 +299,8 @@ static const vcardrestriction_record *vcardrestriction_get_restriction( for (rec = start; rec && rec->restriction != VCARD_RESTRICTION_NONE; rec++) { - if (version == rec->version && + if ((version == VCARD_VERSION_NONE || + rec->version == VCARD_VERSION_NONE || version == rec->version) && (component == VCARD_ANY_COMPONENT || (component == rec->component && (property == VCARD_ANY_PROPERTY || property == rec->property) && diff --git a/src/test/libicalvcard/vcard_test.c b/src/test/libicalvcard/vcard_test.c index a3645561d..05df5ac4e 100644 --- a/src/test/libicalvcard/vcard_test.c +++ b/src/test/libicalvcard/vcard_test.c @@ -15,6 +15,7 @@ #include "vcard.h" +#include #include #include #include @@ -26,6 +27,14 @@ #include #endif +#define assert_str_equals(want, have) \ +{ \ + const char *_w = (want); \ + const char *_h = (have); \ + int _v = strcmp(_w, _h); \ + if (_v) { fprintf(stderr, "line %d: string mismatch\n want=%s\n have=%s\n", __LINE__, _w, _h); assert(0); } \ +} + void strip_errors(vcardcomponent *comp) { vcardproperty *prop, *next; @@ -38,49 +47,90 @@ void strip_errors(vcardcomponent *comp) } } -int main(int argc, const char **argv) +static void test_parse_file(const char *fname) { - int fd; - const char *fname; + int fd, r; struct stat sbuf; size_t filesize; void *data = NULL; + vcardcomponent *card; + const char *want = + "BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "FN:Simon Perreault\r\n" + "N:Perreault;Simon;;;ing. jr,M.Sc.\r\n" + "BDAY;VALUE=DATE:--0203\r\n" + "BDAY;VALUE=DATE:--0203\r\n" + "ANNIVERSARY;VALUE=TIMESTAMP:20090808T143000-0500\r\n" + "GENDER:M;manly\r\n" + "ADR;TYPE=WORK:;Suite D2-630;2875 Laurier;Quebec;QC;G1V 2M2;Canada\r\n" + "TEL;VALUE=URI;TYPE=WORK,TEXT,VOICE,CELL,VIDEO,bar,foo:tel:\r\n" + " +1-418-262-6501\r\n" + "TEL;VALUE=URI:tel:+1-418-656-9254;ext=102\r\n" + "EMAIL;TYPE=WORK:simon.perreault@viagenie.ca\r\n" + "LANG;PREF=2:en\r\n" + "LANG;PREF=1:fr\r\n" + "TZ;VALUE=TEXT:-0500\r\n" + "GEO;TYPE=WORK:geo:46.772673,-71.282945\r\n" + "ORG;TYPE=WORK:Viagenie;Foo\r\n" + "CATEGORIES:bar,foo\r\n" + "NOTE;LANGUAGE=en;PID=1.0,3:Test vCard\r\n" + "URL;TYPE=HOME:http://nomis80.org\r\n" + "KEY;VALUE=URI;TYPE=WORK:http://www.viagenie.ca/simon.perreault/simon.asc\r\n" + "X-LIC-ERROR;X-LIC-ERRORTYPE=RESTRICTION-CHECK:Failed restrictions for \r\n" + " BDAY property. Expected zero or one instances of the property and got 2\r\n" + "END:VCARD\r\n" + "BEGIN:VCARD\r\n" + "FN:Mickey Mouse\r\n" + "X-LIC-ERROR;X-LIC-ERRORTYPE=RESTRICTION-CHECK:Failed restrictions for N \r\n" + " property. Expected 1 instances of the property and got 0\r\n" + "X-LIC-ERROR;X-LIC-ERRORTYPE=RESTRICTION-CHECK:Failed restrictions for \r\n" + " VERSION property. Expected 1 instances of the property and got 0\r\n" + "END:VCARD\r\n"; - if (argc != 2) { - fprintf(stderr, "Usage: %s fname\n", argv[0]); - exit(1); - } - - fname = argv[1]; fd = open(fname, O_RDONLY); if (fd < 0) { fprintf(stderr, "Error: unable to open %s\n", fname); - exit(1); + assert(0); } fstat(fd, &sbuf); filesize = sbuf.st_size; //to make fortify compile happy data = malloc(filesize+1); memset(data, 0, filesize+1); - if (read(fd, data, filesize) < 0) { + + r = read(fd, data, filesize); + close(fd); + + if (r < 0) { fprintf(stderr, "Failed to read vCard\n"); free(data); - close(fd); - return -1; + assert(0); } - vcardcomponent *card = vcardparser_parse_string(data); + card = vcardparser_parse_string(data); free(data); if (card == NULL) { fprintf(stderr, "Failed to parse vCard\n"); - close(fd); - return -1; + assert(0); } vcardrestriction_check(card); vcardcomponent_normalize(card); - printf("%s\n", vcardcomponent_as_vcard_string(card)); + assert_str_equals(want, vcardcomponent_as_vcard_string(card)); vcardcomponent_free(card); +} + +static vcardcomponent *test_comp_vanew(void) +{ + vcardcomponent *card; + const char *want = + "BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "X-LIC-ERROR;X-LIC-ERRORTYPE=RESTRICTION-CHECK:Failed restrictions for FN \r\n" + " property. Expected one or more instances of the property and got 0\r\n" + "END:VCARD\r\n"; + card = vcardcomponent_vanew(VCARD_VCARD_COMPONENT, vcardproperty_new_version(VCARD_VERSION_40), @@ -89,14 +139,31 @@ int main(int argc, const char **argv) if (card == NULL) { fprintf(stderr, "Failed to create vCard\n"); - close(fd); - return -1; + assert(0); } vcardrestriction_check(card); - printf("\n%s\n", vcardcomponent_as_vcard_string(card)); + vcardcomponent_normalize(card); + assert_str_equals(want, vcardcomponent_as_vcard_string(card)); strip_errors(card); + return card; +} + +static void test_add_props(vcardcomponent *card) +{ + const char *want = + "BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "FN:Mickey Mouse\r\n" + "N:Mouse;Mickey;;;;;\r\n" + "BDAY;VALUE=DATE:19281118\r\n" + "ADR:;;123 Main Street,Disney World;Orlando;FL;32836;USA;;;;;;;;;;;\r\n" + "CATEGORIES:aaa,zzz\r\n" + "group1.NOTE;LANGUAGE=en;PID=1,3;SORT-AS=bar,foo;TYPE=WORK:Test vCard\r\n" +// "REV:20240424T143248Z\r\n" + "END:VCARD\r\n"; + /* Create and add NOTE property */ vcardstrarray *sa = vcardstrarray_new(10); vcardstrarray_append(sa, "1"); @@ -173,25 +240,60 @@ int main(int argc, const char **argv) t.day = 18; prop = vcardproperty_new_bday(t); vcardcomponent_add_property(card, prop); - +#if 0 // Can't easily compare /* Create and add REV property */ t = vcardtime_current_utc_time(); prop = vcardproperty_new_rev(t); vcardcomponent_add_property(card, prop); - +#endif vcardrestriction_check(card); vcardcomponent_normalize(card); - printf("\n%s\n", vcardcomponent_as_vcard_string(card)); + assert_str_equals(want, vcardcomponent_as_vcard_string(card)); +} + +static void test_n_restriction(vcardcomponent *card) +{ + vcardproperty *prop; + const char *want = + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Mickey Mouse\r\n" + "BDAY;VALUE=DATE:19281118\r\n" + "ADR:;;123 Main Street,Disney World;Orlando;FL;32836;USA;;;;;;;;;;;\r\n" + "CATEGORIES:aaa,zzz\r\n" + "group1.NOTE;LANGUAGE=en;PID=1,3;SORT-AS=bar,foo;TYPE=WORK:Test vCard\r\n" + "X-LIC-ERROR;X-LIC-ERRORTYPE=RESTRICTION-CHECK:Failed restrictions for N \r\n" + " property. Expected 1 instances of the property and got 0\r\n" + "END:VCARD\r\n"; /* Change VERSION from 4.0 to 3.0 */ prop = vcardcomponent_get_first_property(card, VCARD_VERSION_PROPERTY); vcardproperty_set_version(prop, VCARD_VERSION_30); + /* Remove N property */ + prop = vcardcomponent_get_first_property(card, VCARD_N_PROPERTY); + vcardcomponent_remove_property(card, prop); + vcardproperty_free(prop); + vcardrestriction_check(card); - printf("\n%s\n", vcardcomponent_as_vcard_string(card)); + assert_str_equals(want, vcardcomponent_as_vcard_string(card)); +} + +int main(int argc, const char **argv) +{ + vcardcomponent *card; + + if (argc != 2) { + fprintf(stderr, "Usage: %s fname\n", argv[0]); + exit(1); + } + + test_parse_file(argv[1]); + card = test_comp_vanew(); + test_add_props(card); + test_n_restriction(card); vcardcomponent_free(card); - close(fd); return 0; } diff --git a/test-data/test.vcf b/test-data/test.vcf index dd19bcefc..214bbd2be 100644 --- a/test-data/test.vcf +++ b/test-data/test.vcf @@ -3,6 +3,7 @@ VERSION: 4.0 FN:Simon Perreault N:Perreault;Simon;;;ing. jr,M.Sc. BDAY:--0203 +BDAY:--0203 ANNIVERSARY:20090808T1430-0500 GENDER:M;manly LANG;PREF=1:fr @@ -23,6 +24,5 @@ CATEGORIES:foo,bar END:VCARD BEGIN:VCARD -VERSION:5.0 FN:Mickey Mouse END:VCARD