[evolution-data-server] I#142 - EContact: Define defaults for attributes without TYPE



commit 799475ef8751e83f5b62eba1c5e83506a55789e6
Author: Milan Crha <mcrha redhat com>
Date:   Fri Aug 16 12:14:43 2019 +0200

    I#142 - EContact: Define defaults for attributes without TYPE
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/issues/142

 src/addressbook/libebook-contacts/e-contact.c | 327 +++++++++++--
 tests/libebook-contacts/CMakeLists.txt        |   1 +
 tests/libebook-contacts/test-type-param.c     | 655 ++++++++++++++++++++++++++
 3 files changed, 948 insertions(+), 35 deletions(-)
---
diff --git a/src/addressbook/libebook-contacts/e-contact.c b/src/addressbook/libebook-contacts/e-contact.c
index fa898ecff..334882e6e 100644
--- a/src/addressbook/libebook-contacts/e-contact.c
+++ b/src/addressbook/libebook-contacts/e-contact.c
@@ -58,6 +58,27 @@ struct _EContactPrivate {
        gchar *cached_strings[E_CONTACT_FIELD_LAST];
 };
 
+typedef struct _AttrTypeValue {
+       const gchar *attr_name;
+       const gchar *type_values; /* semicolon-delimited upper-case list of used TYPE values */
+} AttrTypeValue;
+
+static AttrTypeValue glob_attr_type_values[] = {
+       { EVC_ADR, "WORK;HOME;OTHER" },
+       { EVC_KEY, "PGP;X509" },
+       { EVC_LABEL, "WORK;HOME;OTHER" },
+       { EVC_TEL, "WORK;HOME;CAR;CELL;FAX;ISDN;PAGER;PREF;VOICE;" EVC_X_ASSISTANT ";" EVC_X_CALLBACK ";" 
EVC_X_COMPANY ";" EVC_X_RADIO ";" EVC_X_TELEX ";" EVC_X_TTYTDD },
+       { EVC_X_AIM, "WORK;HOME" },
+       { EVC_X_GADUGADU, "WORK;HOME" },
+       { EVC_X_GOOGLE_TALK, "WORK;HOME" },
+       { EVC_X_GROUPWISE, "WORK;HOME" },
+       { EVC_X_ICQ, "WORK;HOME" },
+       { EVC_X_JABBER, "WORK;HOME" },
+       { EVC_X_MSN, "WORK;HOME" },
+       { EVC_X_SKYPE, "WORK;HOME" },
+       { EVC_X_YAHOO, "WORK;HOME" }
+};
+
 #define E_CONTACT_FIELD_TYPE_STRING       0x00000001   /* used for simple single valued attributes */
 /*E_CONTACT_FIELD_TYPE_FLOAT*/
 #define E_CONTACT_FIELD_TYPE_LIST         0x00000002   /* used for multivalued single attributes - the 
elements are of type gchar * */
@@ -153,7 +174,7 @@ static const EContactFieldInfo field_info[] = {
 
        /* Address Labels */
        ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_HOME,  EVC_LABEL, "address_label_home",  N_("Home 
Address Label"),  FALSE, "HOME", 0),
-       ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_WORK,  EVC_LABEL, "address_label_work",  N_("Work 
Address Label"),  FALSE, "WORK", 0),
+       ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_WORK,  EVC_LABEL, "address_label_work",  N_("Work 
Address Label"),  FALSE, "*WORK", 0),
        ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_OTHER, EVC_LABEL, "address_label_other", N_("Other 
Address Label"), FALSE, "OTHER", 0),
 
        /* Phone fields */
@@ -169,7 +190,7 @@ static const EContactFieldInfo field_info[] = {
        ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_FAX,     EVC_TEL, "home_fax",          N_("Home Fax"),     
    FALSE, "HOME", "FAX",           0),
        ATTR_TYPE_STR_FIELD  (E_CONTACT_PHONE_ISDN,         EVC_TEL, "isdn_phone",        N_("ISDN"),         
    FALSE, "ISDN",                  0),
        ATTR_TYPE_STR_FIELD  (E_CONTACT_PHONE_MOBILE,       EVC_TEL, "mobile_phone",      N_("Mobile Phone"), 
    FALSE, "CELL",                  0),
-       ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER,        EVC_TEL, "other_phone",       N_("Other Phone"),  
    FALSE, "VOICE", "",             0),
+       ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER,        EVC_TEL, "other_phone",       N_("Other Phone"),  
    FALSE, "*VOICE", "",            0),
        ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER_FAX,    EVC_TEL, "other_fax",         N_("Other Fax"),    
    FALSE, "FAX", "",               0),
        ATTR_TYPE_STR_FIELD  (E_CONTACT_PHONE_PAGER,        EVC_TEL, "pager",             N_("Pager"),        
    FALSE, "PAGER",                 0),
        ATTR_TYPE_STR_FIELD  (E_CONTACT_PHONE_PRIMARY,      EVC_TEL, "primary_phone",     N_("Primary 
Phone"),    FALSE, "PREF",                  0),
@@ -252,7 +273,7 @@ static const EContactFieldInfo field_info[] = {
        /* Address fields */
        MULTI_LIST_FIELD       (E_CONTACT_ADDRESS,       EVC_ADR, "address",       N_("Address List"),  
FALSE),
        ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_HOME,  EVC_ADR, "address_home",  N_("Home Address"),  
FALSE, "HOME",  adr_getter, adr_setter, e_contact_address_get_type),
-       ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_WORK,  EVC_ADR, "address_work",  N_("Work Address"),  
FALSE, "WORK",  adr_getter, adr_setter, e_contact_address_get_type),
+       ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_WORK,  EVC_ADR, "address_work",  N_("Work Address"),  
FALSE, "*WORK",  adr_getter, adr_setter, e_contact_address_get_type),
        ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_OTHER, EVC_ADR, "address_other", N_("Other Address"), 
FALSE, "OTHER", adr_getter, adr_setter, e_contact_address_get_type),
 
        /* Contact categories */
@@ -334,6 +355,135 @@ static const EContactFieldInfo field_info[] = {
 #undef LIST_FIELD
 #undef GETSET_FIELD
 
+static const AttrTypeValue *
+e_contact_find_attr_type_values (const gchar *attr_name)
+{
+       gint ii;
+
+       g_return_val_if_fail (attr_name != NULL, NULL);
+
+       for (ii = 0; ii < G_N_ELEMENTS (glob_attr_type_values); ii++) {
+               if (g_ascii_strcasecmp (glob_attr_type_values[ii].attr_name, attr_name) == 0) {
+                       return &(glob_attr_type_values[ii]);
+               }
+       }
+
+       g_warn_if_reached ();
+
+       return NULL;
+}
+
+static gboolean
+e_contact_check_attr_type_value_used (const AttrTypeValue *attr_type_values,
+                                     const gchar *type_value)
+{
+       gint ii, pos;
+
+       if (!attr_type_values)
+               return TRUE;
+
+       if (!type_value || !*type_value)
+               return FALSE;
+
+       pos = 0;
+
+       for (ii = 0; attr_type_values->type_values[ii]; ii++) {
+               gboolean skip = FALSE;
+
+               if (attr_type_values->type_values[ii] == g_ascii_toupper (type_value[pos])) {
+                       pos++;
+
+                       if (!type_value[pos]) {
+                               if (attr_type_values->type_values[ii + 1] == 0 || 
attr_type_values->type_values[ii + 1] == ';')
+                                       return TRUE;
+
+                               skip = TRUE;
+                       }
+               } else {
+                       skip = TRUE;
+               }
+
+               if (skip) {
+                       pos = 0;
+
+                       while (attr_type_values->type_values[ii] && attr_type_values->type_values[ii] != ';')
+                               ii++;
+               }
+       }
+
+       return FALSE;
+}
+
+#ifdef ENABLE_MAINTAINER_MODE
+
+static void
+e_contact_maybe_insert_attr_type (GHashTable *used_attr_types,
+                                 const gchar *vcard_field_name,
+                                 const gchar *type_value)
+{
+       g_return_if_fail (used_attr_types != NULL);
+       g_return_if_fail (vcard_field_name != NULL);
+
+       /* Skip leading '*', it denotes default value */
+       if (type_value && *type_value == '*')
+               type_value++;
+
+       if (type_value && *type_value) {
+               GHashTable *types_hash;
+
+               types_hash = g_hash_table_lookup (used_attr_types, vcard_field_name);
+
+               if (!types_hash) {
+                       types_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+                       g_hash_table_insert (used_attr_types, (gpointer) vcard_field_name, types_hash);
+               }
+
+               g_hash_table_insert (types_hash, (gpointer) type_value, NULL);
+       }
+}
+
+static gint
+e_contact_cmp_type_values (gconstpointer v1,
+                          gconstpointer v2)
+{
+       const gchar *type1 = v1, *type2 = v2;
+       gint who1, who2;
+
+       /* Work/Home/Other has precedence over others, in this order */
+       if (g_str_equal (type1, "WORK"))
+               who1 = 3;
+       else if (g_str_equal (type1, "HOME"))
+               who1 = 2;
+       else if (g_str_equal (type1, "OTHER"))
+               who1 = 1;
+       else
+               who1 = -1;
+
+       if (g_str_equal (type2, "WORK"))
+               who2 = 3;
+       else if (g_str_equal (type2, "HOME"))
+               who2 = 2;
+       else if (g_str_equal (type2, "OTHER"))
+               who2 = 1;
+       else
+               who2 = -1;
+
+       if (who1 == -1) {
+               if (who2 == -1)
+                       return g_strcmp0 (type1, type2);
+
+               return 1;
+       }
+
+       if (who2 == -1)
+               return -1;
+
+       return who2 - who1;
+}
+
+#endif /* ENABLE_MAINTAINER_MODE */
+
 static void e_contact_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
 static void e_contact_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
 
@@ -356,6 +506,11 @@ static void
 e_contact_class_init (EContactClass *class)
 {
        GObjectClass *object_class;
+       #ifdef ENABLE_MAINTAINER_MODE
+       GHashTable *used_attr_types; /* gchar *attr_name ~> GHashTable { gchar *type_value ~> NULL } */
+       GHashTableIter iter;
+       gpointer key, value;
+       #endif
        gint ii;
 
        g_type_class_add_private (class, sizeof (EContactPrivate));
@@ -365,6 +520,10 @@ e_contact_class_init (EContactClass *class)
        object_class->get_property = e_contact_get_property;
        object_class->finalize = e_contact_finalize;
 
+       #ifdef ENABLE_MAINTAINER_MODE
+       used_attr_types = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) 
g_hash_table_destroy);
+       #endif
+
        for (ii = E_CONTACT_FIELD_FIRST; ii < E_CONTACT_FIELD_LAST; ii++) {
                GParamSpec *pspec = NULL;
                GParamFlags flags;
@@ -416,7 +575,63 @@ e_contact_class_init (EContactClass *class)
 
                g_object_class_install_property (
                        object_class, field_info[ii].field_id, pspec);
+
+               #ifdef ENABLE_MAINTAINER_MODE
+               if (field_info[ii].t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) {
+                       e_contact_maybe_insert_attr_type (used_attr_types, field_info[ii].vcard_field_name, 
field_info[ii].attr_type1);
+                       e_contact_maybe_insert_attr_type (used_attr_types, field_info[ii].vcard_field_name, 
field_info[ii].attr_type2);
+               }
+               #endif
+       }
+
+       /* To verify whether the static glob_attr_type_values array is filled properly */
+       #ifdef ENABLE_MAINTAINER_MODE
+
+       g_assert_cmpint (g_hash_table_size (used_attr_types), ==, G_N_ELEMENTS (glob_attr_type_values));
+
+       g_hash_table_iter_init (&iter, used_attr_types);
+
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               GHashTableIter iter2;
+               gpointer key2;
+               GSList *values = NULL, *link;
+               GString *expected;
+               const AttrTypeValue *attr_data;
+
+               g_hash_table_iter_init (&iter2, value);
+               while (g_hash_table_iter_next (&iter2, &key2, NULL)) {
+                       const gchar *type_value = key2;
+
+                       for (ii = 0; type_value && type_value[ii]; ii++) {
+                               /* Verify strings are in upper-case */
+                               g_assert_cmpint (g_ascii_toupper (type_value[ii]), ==, type_value[ii]);
+                       }
+
+                       values = g_slist_prepend (values, (gpointer) type_value);
+               }
+
+               values = g_slist_sort (values, e_contact_cmp_type_values);
+
+               expected = g_string_new ("");
+
+               for (link = values; link; link = g_slist_next (link)) {
+                       g_string_append (expected, link->data);
+
+                       if (link->next)
+                               g_string_append_c (expected, ';');
+               }
+
+               attr_data = e_contact_find_attr_type_values (key);
+               g_assert_nonnull (attr_data);
+               g_assert_cmpstr (attr_data->type_values, ==, expected->str);
+
+               g_slist_free (values);
+               g_string_free (expected, TRUE);
        }
+
+       g_hash_table_destroy (used_attr_types);
+
+       #endif /* ENABLE_MAINTAINER_MODE */
 }
 
 static void
@@ -859,12 +1074,28 @@ e_contact_find_attribute_with_types (EContact *contact,
                                      gint nth)
 {
        GList *l, *attrs;
+       const AttrTypeValue *attr_type_values;
        gboolean found_needed1, found_needed2;
        gboolean can_empty_needed2;
+       gboolean use_for_no_type;
 
        can_empty_needed2 = g_ascii_strcasecmp (attr_name, "TEL") == 0 && type_needed2 &&
                            g_ascii_strcasecmp (type_needed2, "VOICE") == 0;
 
+       attr_type_values = e_contact_find_attr_type_values (attr_name);
+
+       /* The first type can start with a '*', which means that the found attribute
+          can be also the one with no type specified. It's used for default types
+          per RFC2426.*/
+       use_for_no_type = type_needed1 && (*type_needed1) == '*';
+
+       if (use_for_no_type) {
+               type_needed1++;
+
+               if (!*type_needed1)
+                       type_needed1 = NULL;
+       }
+
        attrs = e_vcard_get_attributes (E_VCARD (contact));
 
        for (l = attrs; l; l = l->next) {
@@ -877,56 +1108,82 @@ e_contact_find_attribute_with_types (EContact *contact,
                name = e_vcard_attribute_get_name (attr);
 
                if (!g_ascii_strcasecmp (name, attr_name)) {
+                       GSList *found_types = NULL;
                        GList *params;
+                       guint n_types = 0, n_found_types = 0;
 
                        for (params = e_vcard_attribute_get_params (attr); params; params = params->next) {
                                EVCardAttributeParam *param = params->data;
                                const gchar *param_name = e_vcard_attribute_param_get_name (param);
-                               gint n_types = 0;
 
                                if (!g_ascii_strcasecmp (param_name, EVC_TYPE)) {
-                                       gboolean matches = FALSE;
-                                       GList *values = e_vcard_attribute_param_get_values (param);
+                                       GList *value;
 
-                                       /* empty string on type_needed2 is to get only those attributes,
-                                        * which has exactly one TYPE, to not rewrite those with multiple */
-                                       if (type_needed2 && !*type_needed2)
-                                               found_needed2 = values && !values->next;
+                                       for (value = e_vcard_attribute_param_get_values (param);
+                                            value;
+                                            value = g_list_next (value)) {
+                                               const gchar *type_value = value->data;
 
-                                       while (values && values->data) {
                                                n_types++;
 
-                                               if (!found_needed1 && !g_ascii_strcasecmp ((gchar *) 
values->data, type_needed1)) {
-                                                       found_needed1 = TRUE;
-                                                       matches = TRUE;
-                                               } else if (!found_needed2 && !g_ascii_strcasecmp ((gchar *) 
values->data, type_needed2)) {
-                                                       found_needed2 = TRUE;
-                                                       matches = TRUE;
-                                               } else if (found_needed1) {
-                                                       if (!matches || !found_needed2)
-                                                               matches = FALSE;
-                                                       break;
+                                               /* Skip any type values which are not used, thus they do not 
confuse the search */
+                                               if (type_value && *type_value &&
+                                                   e_contact_check_attr_type_value_used (attr_type_values, 
type_value)) {
+                                                       found_types = g_slist_prepend (found_types, 
(gpointer) type_value);
+                                                       n_found_types++;
                                                }
-                                               values = values->next;
                                        }
+                               }
+                       }
 
-                                       if (!matches && (!can_empty_needed2 || n_types != 1)) {
-                                               /* this is to enforce that we find an attribute
-                                                * with *only* the TYPE='s we need.  This may seem like
-                                                * an odd restriction but it's the only way at present to
-                                                * implement the Other Fax and Other Phone attributes. */
-                                               found_needed1 = FALSE;
+                       if (!n_types) {
+                               if (use_for_no_type && (nth-- == 0))
+                                       return attr;
+                       } else {
+                               GSList *link;
+                               gboolean matches = FALSE;
+
+                               /* empty string on type_needed2 is to get only those attributes,
+                                * which has exactly one TYPE, to not rewrite those with multiple */
+                               if (type_needed2 && !*type_needed2)
+                                       found_needed2 = n_found_types == 1;
+
+                               for (link = found_types; link; link = g_slist_next (link)) {
+                                       const gchar *type_value = link->data;
+
+                                       if (!type_value)
+                                               continue;
+
+                                       if (!found_needed1 && !g_ascii_strcasecmp (type_value, type_needed1)) 
{
+                                               found_needed1 = TRUE;
+                                               matches = TRUE;
+                                       } else if (!found_needed2 && !g_ascii_strcasecmp (type_value, 
type_needed2)) {
+                                               found_needed2 = TRUE;
+                                               matches = TRUE;
+                                       } else if (found_needed1) {
+                                               if (!found_needed2)
+                                                       matches = FALSE;
                                                break;
                                        }
                                }
 
-                               if (found_needed1 && (found_needed2 || (n_types == 1 && can_empty_needed2))) {
-                                       if (nth-- == 0)
+                               if (!matches && (!can_empty_needed2 || n_found_types != 1)) {
+                                       /* this is to enforce that we find an attribute
+                                        * with *only* the TYPE='s we need.  This may seem like
+                                        * an odd restriction but it's the only way at present to
+                                        * implement the Other Fax and Other Phone attributes. */
+                                       found_needed1 = FALSE;
+                               }
+
+                               if (found_needed1 && (found_needed2 || (n_found_types == 1 && 
can_empty_needed2))) {
+                                       if (nth-- == 0) {
+                                               g_slist_free (found_types);
                                                return attr;
-                                       else
-                                               break;
+                                       }
                                }
                        }
+
+                       g_slist_free (found_types);
                }
        }
 
@@ -1004,7 +1261,7 @@ e_contact_set_property (GObject *object,
                                        /* we didn't find it - add a new attribute */
                                        attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
                                        if (!g_ascii_strcasecmp (info->vcard_field_name, "EMAIL") &&
-                                           !info->attr_type1 &&
+                                           (!info->attr_type1 || (info->attr_type1[0] == '*' && 
!info->attr_type1[1])) &&
                                            (!info->attr_type2 || !*info->attr_type2)) {
                                                /* Add default type */
                                                e_vcard_attribute_add_param_with_value (
@@ -1039,10 +1296,10 @@ e_contact_set_property (GObject *object,
                                /* we didn't find it - add a new attribute */
                                attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
                                e_vcard_append_attribute (E_VCARD (contact), attr);
-                               if (info->attr_type1)
+                               if (info->attr_type1 && (info->attr_type1[0] != '*' || info->attr_type1[1]))
                                        e_vcard_attribute_add_param_with_value (
                                                attr, e_vcard_attribute_param_new (EVC_TYPE),
-                                               info->attr_type1);
+                                               info->attr_type1[0] == '*' ? info->attr_type1 + 1 : 
info->attr_type1);
                                if (info->attr_type2 && *info->attr_type2)
                                        e_vcard_attribute_add_param_with_value (
                                                attr, e_vcard_attribute_param_new (EVC_TYPE),
diff --git a/tests/libebook-contacts/CMakeLists.txt b/tests/libebook-contacts/CMakeLists.txt
index bd68cdacb..7649a3892 100644
--- a/tests/libebook-contacts/CMakeLists.txt
+++ b/tests/libebook-contacts/CMakeLists.txt
@@ -21,6 +21,7 @@ set(TESTS
        test-contact-types
        test-vcard-parsing
        test-untyped-phones
+       test-type-param
        test-query
        test-phone-number
 )
diff --git a/tests/libebook-contacts/test-type-param.c b/tests/libebook-contacts/test-type-param.c
new file mode 100644
index 000000000..3e654a5d3
--- /dev/null
+++ b/tests/libebook-contacts/test-type-param.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libebook-contacts/libebook-contacts.h>
+
+typedef struct _TestData {
+       const gchar *vcard_str;
+       EContactField field_id;
+       const gchar *expected;
+} TestData;
+
+static void
+test_type_param (const TestData datas[],
+                guint n_datas,
+                void (* check_value_func) (gconstpointer value,
+                                           const gchar *expected),
+                GDestroyNotify free_value_func)
+{
+       const gchar *vcard_str = NULL;
+       guint ii;
+
+       for (ii = 0; ii < n_datas; ii++) {
+               EContact *contact;
+               gpointer value;
+
+               /* Items can inherit the vCard definition */
+               if (datas[ii].vcard_str)
+                       vcard_str = datas[ii].vcard_str;
+
+               g_assert_nonnull (vcard_str);
+
+               contact = e_contact_new_from_vcard (vcard_str);
+               g_assert_nonnull (contact);
+
+               value = e_contact_get (contact, datas[ii].field_id);
+
+               if (datas[ii].expected) {
+                       g_assert_nonnull (value);
+
+                       if (check_value_func)
+                               check_value_func (value, datas[ii].expected);
+                       else
+                               g_assert_cmpstr (value, ==, datas[ii].expected);
+               } else {
+                       g_assert_null (value);
+               }
+
+               if (free_value_func)
+                       free_value_func (value);
+               else
+                       g_free (value);
+
+               g_object_unref (contact);
+       }
+}
+
+static void
+test_type_param_email (void)
+{
+       TestData datas[] = {
+               { "BEGIN:VCARD\r\n"
+                 "EMAIL;TYPE=home:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_EMAIL_1, "V1" },
+               { NULL, E_CONTACT_EMAIL_2, NULL },
+               { NULL, E_CONTACT_EMAIL_3, NULL },
+               { NULL, E_CONTACT_EMAIL_4, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "EMAIL;TYPE=home:V1\r\n"
+                 "EMAIL;TYPE=home:V2\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_EMAIL_1, "V1" },
+               { NULL, E_CONTACT_EMAIL_2, "V2" },
+               { NULL, E_CONTACT_EMAIL_3, NULL },
+               { NULL, E_CONTACT_EMAIL_4, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "EMAIL;TYPE=home:V1\r\n"
+                 "EMAIL;TYPE=home:V2\r\n"
+                 "EMAIL;TYPE=home:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_EMAIL_1, "V1" },
+               { NULL, E_CONTACT_EMAIL_2, "V2" },
+               { NULL, E_CONTACT_EMAIL_3, "V3" },
+               { NULL, E_CONTACT_EMAIL_4, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "EMAIL;TYPE=home:V1\r\n"
+                 "EMAIL;TYPE=home:V2\r\n"
+                 "EMAIL;TYPE=home:V3\r\n"
+                 "EMAIL;TYPE=home:V4\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_EMAIL_1, "V1" },
+               { NULL, E_CONTACT_EMAIL_2, "V2" },
+               { NULL, E_CONTACT_EMAIL_3, "V3" },
+               { NULL, E_CONTACT_EMAIL_4, "V4" },
+               { "BEGIN:VCARD\r\n"
+                 "EMAIL;TYPE=home:V1\r\n"
+                 "EMAIL;TYPE=home:V2\r\n"
+                 "EMAIL;TYPE=home:V3\r\n"
+                 "EMAIL;TYPE=home:V4\r\n"
+                 "EMAIL;TYPE=home:V5\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_EMAIL_1, "V1" },
+               { NULL, E_CONTACT_EMAIL_2, "V2" },
+               { NULL, E_CONTACT_EMAIL_3, "V3" },
+               { NULL, E_CONTACT_EMAIL_4, "V4" }
+       };
+
+       test_type_param (datas, G_N_ELEMENTS (datas), NULL, NULL);
+}
+
+static void
+check_value_adr (gconstpointer value,
+                const gchar *expected)
+{
+       const EContactAddress *addr = value;
+
+       g_assert_nonnull (addr);
+       g_assert_nonnull (expected);
+
+       g_assert_cmpstr (addr->street, ==, expected);
+}
+
+static void
+test_type_param_adr (void)
+{
+       TestData datas[] = {
+               { "BEGIN:VCARD\r\n"
+                 "ADR;TYPE=home:;;V1;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, "V1" },
+               { NULL, E_CONTACT_ADDRESS_WORK, NULL },
+               { NULL, E_CONTACT_ADDRESS_OTHER, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "ADR:;;V1;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_WORK, "V1" },
+               { NULL, E_CONTACT_ADDRESS_OTHER, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "ADR;TYPE=work:;;V1;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_WORK, "V1" },
+               { NULL, E_CONTACT_ADDRESS_OTHER, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "ADR;TYPE=other:;;V1;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_WORK, NULL },
+               { NULL, E_CONTACT_ADDRESS_OTHER, "V1" },
+               { "BEGIN:VCARD\r\n"
+                 "ADR;TYPE=dom;TYPE=home:;;V1;;;;\r\n"
+                 "ADR;TYPE=postal,work:;;V2;;;;\r\n"
+                 "ADR;TYPE=postal,intl;TYPE=parcel,other:;;V3;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, "V1" },
+               { NULL, E_CONTACT_ADDRESS_WORK, "V2" },
+               { NULL, E_CONTACT_ADDRESS_OTHER, "V3" },
+               { "BEGIN:VCARD\r\n"
+                 "ADR:;;V1;;;;\r\n"
+                 "ADR;TYPE=dom;TYPE=home:;;V2;;;;\r\n"
+                 "ADR;TYPE=postal,intl;TYPE=parcel,other:;;V3;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, "V2" },
+               { NULL, E_CONTACT_ADDRESS_WORK, "V1" },
+               { NULL, E_CONTACT_ADDRESS_OTHER, "V3" },
+               { "BEGIN:VCARD\r\n"
+                 "ADR;TYPE=dom:;;V1;;;;\r\n"
+                 "ADR:;;V2;;;;\r\n"
+                 "ADR;TYPE=postal,intl;TYPE=parcel,other:;;V3;;;;\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_WORK, "V2" },
+               { NULL, E_CONTACT_ADDRESS_OTHER, "V3" }
+       };
+
+       test_type_param (datas, G_N_ELEMENTS (datas), check_value_adr, (GDestroyNotify) 
e_contact_address_free);
+}
+
+static void
+test_type_param_label (void)
+{
+       TestData datas[] = {
+               { "BEGIN:VCARD\r\n"
+                 "LABEL;TYPE=home:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, "V1" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, NULL },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "LABEL:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, "V1" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "LABEL;TYPE=work:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, "V1" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "LABEL;TYPE=other:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, NULL },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, "V1" },
+               { "BEGIN:VCARD\r\n"
+                 "LABEL;TYPE=dom;TYPE=home:V1\r\n"
+                 "LABEL;TYPE=postal,work:V2\r\n"
+                 "LABEL;TYPE=postal,intl;TYPE=parcel,other:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, "V1" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, "V2" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, "V3" },
+               { "BEGIN:VCARD\r\n"
+                 "LABEL:V1\r\n"
+                 "LABEL;TYPE=dom;TYPE=home:V2\r\n"
+                 "LABEL;TYPE=postal,intl;TYPE=parcel,other:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, "V2" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, "V1" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, "V3" },
+               { "BEGIN:VCARD\r\n"
+                 "LABEL;TYPE=dom:V1\r\n"
+                 "LABEL:V2\r\n"
+                 "LABEL;TYPE=postal,intl;TYPE=parcel,other:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_ADDRESS_LABEL_HOME, NULL },
+               { NULL, E_CONTACT_ADDRESS_LABEL_WORK, "V2" },
+               { NULL, E_CONTACT_ADDRESS_LABEL_OTHER, "V3" }
+       };
+
+       test_type_param (datas, G_N_ELEMENTS (datas), NULL, NULL);
+}
+
+static void
+check_value_key (gconstpointer value,
+                const gchar *expected)
+{
+       const EContactCert *cert = value;
+       gchar *str_cert;
+
+       g_assert_nonnull (cert);
+       g_assert_nonnull (expected);
+
+       str_cert = g_strndup (cert->data, cert->length);
+
+       g_assert_cmpstr (str_cert, ==, expected);
+
+       g_free (str_cert);
+}
+
+static void
+test_type_param_key (void)
+{
+       TestData datas[] = {
+               { "BEGIN:VCARD\r\n"
+                 "KEY;TYPE=x509:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_X509_CERT, "V1" },
+               { NULL, E_CONTACT_PGP_CERT, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "KEY;TYPE=pgp:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_X509_CERT, NULL },
+               { NULL, E_CONTACT_PGP_CERT, "V1" },
+               { "BEGIN:VCARD\r\n"
+                 "KEY;TYPE=X509;TYPE=x-test:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_X509_CERT, "V1" },
+               { NULL, E_CONTACT_PGP_CERT, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "KEY;TYPE=PGP;TYPE=x-test:V1\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_X509_CERT, NULL },
+               { NULL, E_CONTACT_PGP_CERT, "V1" },
+               { "BEGIN:VCARD\r\n"
+                 "KEY;TYPE=x-test,x509:V1\r\n"
+                 "KEY;TYPE=x-test,pgp:V2\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_X509_CERT, "V1" },
+               { NULL, E_CONTACT_PGP_CERT, "V2" },
+               { "BEGIN:VCARD\r\n"
+                 "KEY:V1\r\n"
+                 "KEY;TYPE=x-test:V2\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_X509_CERT, NULL },
+               { NULL, E_CONTACT_PGP_CERT, NULL }
+       };
+
+       test_type_param (datas, G_N_ELEMENTS (datas), check_value_key, (GDestroyNotify) e_contact_cert_free);
+}
+
+static void
+test_type_param_tel (void)
+{
+       TestData datas[] = {
+               { "BEGIN:VCARD\r\n"
+                 "TEL;TYPE=" EVC_X_ASSISTANT ":V1\r\n"
+                 "TEL;TYPE=work:V2\r\n"
+                 "TEL;TYPE=work,voice:V3\r\n"
+                 "TEL;TYPE=work;TYPE=fax:V4\r\n"
+                 "TEL;TYPE=" EVC_X_CALLBACK ":V5\r\n"
+                 "TEL;TYPE=car:V6\r\n"
+                 "TEL;TYPE=" EVC_X_COMPANY ":V7\r\n"
+                 "TEL;TYPE=voice,home:V8\r\n"
+                 "TEL;TYPE=home:V9\r\n"
+                 "TEL;TYPE=fax;Type=home:V10\r\n"
+                 "TEL;TYPE=ISDN:V11\r\n"
+                 "TEL;TYPE=cell:V12\r\n"
+                 "TEL;TYPE=voice:V13\r\n"
+                 "TEL;TYPE=fax:V14\r\n"
+                 "TEL;TYPE=pager:V15\r\n"
+                 "TEL;TYPE=pref:V16\r\n"
+                 "TEL;TYPE=" EVC_X_RADIO ":V17\r\n"
+                 "TEL;TYPE=" EVC_X_TELEX ":V18\r\n"
+                 "TEL;TYPE=" EVC_X_TTYTDD ":V19\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_PHONE_ASSISTANT, "V1" },
+               { NULL, E_CONTACT_PHONE_BUSINESS, "V2" },
+               { NULL, E_CONTACT_PHONE_BUSINESS_2, "V3" },
+               { NULL, E_CONTACT_PHONE_BUSINESS_FAX, "V4" },
+               { NULL, E_CONTACT_PHONE_CALLBACK, "V5" },
+               { NULL, E_CONTACT_PHONE_CAR, "V6" },
+               { NULL, E_CONTACT_PHONE_COMPANY, "V7" },
+               { NULL, E_CONTACT_PHONE_HOME, "V8" },
+               { NULL, E_CONTACT_PHONE_HOME_2, "V9" },
+               { NULL, E_CONTACT_PHONE_HOME_FAX, "V10" },
+               { NULL, E_CONTACT_PHONE_ISDN, "V11" },
+               { NULL, E_CONTACT_PHONE_MOBILE, "V12" },
+               { NULL, E_CONTACT_PHONE_OTHER, "V13" },
+               { NULL, E_CONTACT_PHONE_OTHER_FAX, "V14" },
+               { NULL, E_CONTACT_PHONE_PAGER, "V15" },
+               { NULL, E_CONTACT_PHONE_PRIMARY, "V16" },
+               { NULL, E_CONTACT_PHONE_RADIO, "V17" },
+               { NULL, E_CONTACT_PHONE_TELEX, "V18" },
+               { NULL, E_CONTACT_PHONE_TTYTDD, "V19" },
+               { "BEGIN:VCARD\r\n"
+                 "TEL;TYPE=" EVC_X_ASSISTANT ";Type=msg:V1\r\n"
+                 "TEL;Type=msg;TYPE=work:V2\r\n"
+                 "TEL;TYPE=work,msg;type=Voice:V3\r\n"
+                 "TEL;TYPE=work;Type=msg;TYPE=fax:V4\r\n"
+                 "TEL;TYPE=msg," EVC_X_CALLBACK ":V5\r\n"
+                 "TEL;TYPE=msg,car:V6\r\n"
+                 "TEL;TYPE=" EVC_X_COMPANY ",msg:V7\r\n"
+                 "TEL;TYPE=voice,msg,home:V8\r\n"
+                 "TEL;TYPE=home,msg:V9\r\n"
+                 "TEL;TYPE=fax,msg;Type=home:V10\r\n"
+                 "TEL;TYPE=msg,Isdn:V11\r\n"
+                 "TEL;TYPE=cELL,msg:V12\r\n"
+                 "TEL:V13\r\n"
+                 "TEL;TYPE=fax,msg:V14\r\n"
+                 "TEL;TYPE=pager,msg:V15\r\n"
+                 "TEL;TYPE=pref,msg:V16\r\n"
+                 "TEL;TYPE=msg," EVC_X_RADIO ":V17\r\n"
+                 "TEL;Type=msg;TYPE=" EVC_X_TELEX ":V18\r\n"
+                 "TEL;TYPE=" EVC_X_TTYTDD ";Type=msg:V19\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_PHONE_ASSISTANT, "V1" },
+               { NULL, E_CONTACT_PHONE_BUSINESS, "V2" },
+               { NULL, E_CONTACT_PHONE_BUSINESS_2, "V3" },
+               { NULL, E_CONTACT_PHONE_BUSINESS_FAX, "V4" },
+               { NULL, E_CONTACT_PHONE_CALLBACK, "V5" },
+               { NULL, E_CONTACT_PHONE_CAR, "V6" },
+               { NULL, E_CONTACT_PHONE_COMPANY, "V7" },
+               { NULL, E_CONTACT_PHONE_HOME, "V8" },
+               { NULL, E_CONTACT_PHONE_HOME_2, "V9" },
+               { NULL, E_CONTACT_PHONE_HOME_FAX, "V10" },
+               { NULL, E_CONTACT_PHONE_ISDN, "V11" },
+               { NULL, E_CONTACT_PHONE_MOBILE, "V12" },
+               { NULL, E_CONTACT_PHONE_OTHER, "V13" },
+               { NULL, E_CONTACT_PHONE_OTHER_FAX, "V14" },
+               { NULL, E_CONTACT_PHONE_PAGER, "V15" },
+               { NULL, E_CONTACT_PHONE_PRIMARY, "V16" },
+               { NULL, E_CONTACT_PHONE_RADIO, "V17" },
+               { NULL, E_CONTACT_PHONE_TELEX, "V18" },
+               { NULL, E_CONTACT_PHONE_TTYTDD, "V19" },
+               { "BEGIN:VCARD\r\n"
+                 "TEL;Type=msg:V1\r\n"
+                 "TEL;TYPE=msg;type=Voice:V2\r\n"
+                 "TEL:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_PHONE_ASSISTANT, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_2, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_CALLBACK, NULL },
+               { NULL, E_CONTACT_PHONE_CAR, NULL },
+               { NULL, E_CONTACT_PHONE_COMPANY, NULL },
+               { NULL, E_CONTACT_PHONE_HOME, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_2, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_ISDN, NULL },
+               { NULL, E_CONTACT_PHONE_MOBILE, NULL },
+               { NULL, E_CONTACT_PHONE_OTHER, "V2" },
+               { NULL, E_CONTACT_PHONE_OTHER_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_PAGER, NULL },
+               { NULL, E_CONTACT_PHONE_PRIMARY, NULL },
+               { NULL, E_CONTACT_PHONE_RADIO, NULL },
+               { NULL, E_CONTACT_PHONE_TELEX, NULL },
+               { NULL, E_CONTACT_PHONE_TTYTDD, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "TEL;Type=msg:V1\r\n"
+                 "TEL:V2\r\n"
+                 "TEL;TYPE=msg;type=Voice:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_PHONE_ASSISTANT, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_2, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_CALLBACK, NULL },
+               { NULL, E_CONTACT_PHONE_CAR, NULL },
+               { NULL, E_CONTACT_PHONE_COMPANY, NULL },
+               { NULL, E_CONTACT_PHONE_HOME, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_2, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_ISDN, NULL },
+               { NULL, E_CONTACT_PHONE_MOBILE, NULL },
+               { NULL, E_CONTACT_PHONE_OTHER, "V2" },
+               { NULL, E_CONTACT_PHONE_OTHER_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_PAGER, NULL },
+               { NULL, E_CONTACT_PHONE_PRIMARY, NULL },
+               { NULL, E_CONTACT_PHONE_RADIO, NULL },
+               { NULL, E_CONTACT_PHONE_TELEX, NULL },
+               { NULL, E_CONTACT_PHONE_TTYTDD, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "TEL;Type=msg:V1\r\n"
+                 "TEL;TYPE=msg;type=Fax:V2\r\n"
+                 "TEL:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_PHONE_ASSISTANT, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_2, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_CALLBACK, NULL },
+               { NULL, E_CONTACT_PHONE_CAR, NULL },
+               { NULL, E_CONTACT_PHONE_COMPANY, NULL },
+               { NULL, E_CONTACT_PHONE_HOME, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_2, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_ISDN, NULL },
+               { NULL, E_CONTACT_PHONE_MOBILE, NULL },
+               { NULL, E_CONTACT_PHONE_OTHER, "V3" },
+               { NULL, E_CONTACT_PHONE_OTHER_FAX, "V2" },
+               { NULL, E_CONTACT_PHONE_PAGER, NULL },
+               { NULL, E_CONTACT_PHONE_PRIMARY, NULL },
+               { NULL, E_CONTACT_PHONE_RADIO, NULL },
+               { NULL, E_CONTACT_PHONE_TELEX, NULL },
+               { NULL, E_CONTACT_PHONE_TTYTDD, NULL },
+               { "BEGIN:VCARD\r\n"
+                 "TEL;Type=msg:V1\r\n"
+                 "TEL:V2\r\n"
+                 "TEL;TYPE=msg;type=Fax:V3\r\n"
+                 "END:VCARD\r\n",
+                 E_CONTACT_PHONE_ASSISTANT, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_2, NULL },
+               { NULL, E_CONTACT_PHONE_BUSINESS_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_CALLBACK, NULL },
+               { NULL, E_CONTACT_PHONE_CAR, NULL },
+               { NULL, E_CONTACT_PHONE_COMPANY, NULL },
+               { NULL, E_CONTACT_PHONE_HOME, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_2, NULL },
+               { NULL, E_CONTACT_PHONE_HOME_FAX, NULL },
+               { NULL, E_CONTACT_PHONE_ISDN, NULL },
+               { NULL, E_CONTACT_PHONE_MOBILE, NULL },
+               { NULL, E_CONTACT_PHONE_OTHER, "V2" },
+               { NULL, E_CONTACT_PHONE_OTHER_FAX, "V3" },
+               { NULL, E_CONTACT_PHONE_PAGER, NULL },
+               { NULL, E_CONTACT_PHONE_PRIMARY, NULL },
+               { NULL, E_CONTACT_PHONE_RADIO, NULL },
+               { NULL, E_CONTACT_PHONE_TELEX, NULL },
+               { NULL, E_CONTACT_PHONE_TTYTDD, NULL }
+       };
+
+       test_type_param (datas, G_N_ELEMENTS (datas), NULL, NULL);
+}
+
+static void
+test_type_param_im (const gchar *im_attr,
+                   gint first_im_field_id)
+{
+       TestData datas[] = {
+               { NULL, -1, "V1" }, /* vcard[0] */
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, NULL }, /* vcard[1] */
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, "V1" },
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, "V2" }, /* vcard[2] */
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, "V1" },
+               { NULL, -1, NULL },
+               { NULL, -1, NULL },
+               { NULL, -1, "V6" }, /* vcard[3] */
+               { NULL, -1, "V7" },
+               { NULL, -1, "V8" },
+               { NULL, -1, "V1" },
+               { NULL, -1, "V2" },
+               { NULL, -1, "V4" }
+       };
+       gchar *vcards[4];
+       gint ii;
+
+       vcards[0] = g_strdup_printf (
+               "BEGIN:VCARD\r\n"
+               "%s;Type=home:V1\r\n"
+               "END:VCARD\r\n",
+               im_attr);
+
+       vcards[1] = g_strdup_printf (
+               "BEGIN:VCARD\r\n"
+               "%s;TYPE=WORK:V1\r\n"
+               "END:VCARD\r\n",
+               im_attr);
+
+       vcards[2] = g_strdup_printf (
+               "BEGIN:VCARD\r\n"
+               "%s;TYPE=x-test,WORK:V1\r\n"
+               "%s;type=X-Test;tYPE=Home:V2\r\n"
+               "END:VCARD\r\n",
+               im_attr, im_attr);
+
+       vcards[3] = g_strdup_printf (
+               "BEGIN:VCARD\r\n"
+               "%s;type=WORK:V1\r\n"
+               "%s;TYPE=x-test,work:V2\r\n"
+               "%s:V3\r\n"
+               "%s;TYPE=WORK,x-test:V4\r\n"
+               "%s:V5\r\n"
+               "%s;type=X-Test;tYPE=Home:V6\r\n"
+               "%s;tYPE=Home;type=X-Test:V7\r\n"
+               "%s;type=Home:V8\r\n"
+               "END:VCARD\r\n",
+               im_attr, im_attr, im_attr, im_attr, im_attr, im_attr, im_attr, im_attr);
+
+       for (ii = 0; ii < G_N_ELEMENTS (datas); ii++) {
+               if (!(ii % 6)) {
+                       g_assert_cmpint (ii / 6, <, G_N_ELEMENTS (vcards));
+
+                       datas[ii].vcard_str = vcards[ii / 6];
+               }
+
+               datas[ii].field_id = first_im_field_id + (ii % 6);
+       }
+
+       test_type_param (datas, G_N_ELEMENTS (datas), NULL, NULL);
+
+       for (ii = 0; ii < G_N_ELEMENTS (vcards); ii++) {
+               g_free (vcards[ii]);
+       }
+}
+
+static void
+test_type_param_xaim (void)
+{
+       test_type_param_im (EVC_X_AIM, E_CONTACT_IM_AIM_HOME_1);
+}
+
+static void
+test_type_param_xgadugadu (void)
+{
+       test_type_param_im (EVC_X_GADUGADU, E_CONTACT_IM_GADUGADU_HOME_1);
+}
+
+static void
+test_type_param_xgoogletalk (void)
+{
+       test_type_param_im (EVC_X_GOOGLE_TALK, E_CONTACT_IM_GOOGLE_TALK_HOME_1);
+}
+
+static void
+test_type_param_xgroupwise (void)
+{
+       test_type_param_im (EVC_X_GROUPWISE, E_CONTACT_IM_GROUPWISE_HOME_1);
+}
+
+static void
+test_type_param_xicq (void)
+{
+       test_type_param_im (EVC_X_ICQ, E_CONTACT_IM_ICQ_HOME_1);
+}
+
+static void
+test_type_param_xjabber (void)
+{
+       test_type_param_im (EVC_X_JABBER, E_CONTACT_IM_JABBER_HOME_1);
+}
+
+static void
+test_type_param_xmsn (void)
+{
+       test_type_param_im (EVC_X_MSN, E_CONTACT_IM_MSN_HOME_1);
+}
+
+static void
+test_type_param_xskype (void)
+{
+       test_type_param_im (EVC_X_SKYPE, E_CONTACT_IM_SKYPE_HOME_1);
+}
+
+static void
+test_type_param_xyahoo (void)
+{
+       test_type_param_im (EVC_X_YAHOO, E_CONTACT_IM_YAHOO_HOME_1);
+}
+
+gint
+main (gint argc,
+      gchar **argv)
+{
+       g_test_init (&argc, &argv, NULL);
+       g_test_bug_base ("https://gitlab.gnome.org/GNOME/evolution-data-server/issues/";);
+
+       g_test_add_func ("/Contact/TypeParam/Email", test_type_param_email);
+       g_test_add_func ("/Contact/TypeParam/Adr", test_type_param_adr);
+       g_test_add_func ("/Contact/TypeParam/Label", test_type_param_label);
+       g_test_add_func ("/Contact/TypeParam/Key", test_type_param_key);
+       g_test_add_func ("/Contact/TypeParam/Tel", test_type_param_tel);
+       g_test_add_func ("/Contact/TypeParam/XAim", test_type_param_xaim);
+       g_test_add_func ("/Contact/TypeParam/XGadugadu", test_type_param_xgadugadu);
+       g_test_add_func ("/Contact/TypeParam/XGoogletalk", test_type_param_xgoogletalk);
+       g_test_add_func ("/Contact/TypeParam/XGroupwise", test_type_param_xgroupwise);
+       g_test_add_func ("/Contact/TypeParam/XIcq", test_type_param_xicq);
+       g_test_add_func ("/Contact/TypeParam/XJabber", test_type_param_xjabber);
+       g_test_add_func ("/Contact/TypeParam/XMsn", test_type_param_xmsn);
+       g_test_add_func ("/Contact/TypeParam/XSkype", test_type_param_xskype);
+       g_test_add_func ("/Contact/TypeParam/XYahoo", test_type_param_xyahoo);
+
+       return g_test_run ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]