summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorNiels De Graef <nielsdegraef@gmail.com>2021-01-11 19:22:17 +0100
committerNiels De Graef <nielsdegraef@gmail.com>2022-08-06 12:45:49 +0200
commitfcbc87c40406b322513c209844d3430bc4108b13 (patch)
tree74efc305e00d893a72b3c8fb22017435b6792111 /tests
parentf37176d5e04b3dc7cc2ad8cb9843d7d7fc35485e (diff)
downloadgnome-contacts-fcbc87c40406b322513c209844d3430bc4108b13.tar.gz
Enable importing & exporting VCards
This commit adds the experimental functionality in Contacts to import VCard (*.vcf) files. Since importing a contact means we have to take in untrusted/unvalidated input, let's give a high-level view of what happens: * Contacts starts a native file chooser dialog so the user can choose which file to import * According to the chosen file, Contacts will launch a subprocess to do the actual parsing using a `Contacts.Io.Parser`. At this point, we only have a single subclass, which allows importing VCards. * The helper process serializes the result to a `GLib.Variant`, and sends it to the main process, which will receive the result and parses it again. * After the parsing operation is done, we can then start up a `ImportOperation`, which will import the contacts using libfolks' API. Exporting contacts is quite a bit easier, since we don't have to deal with untrusted input: we serialize the list of selected contacts and asynchronously write each to the given output stream. In the app, that's a user chosen file; in tests, that can be a string. Fixes: https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/1 Fixes: https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/38
Diffstat (limited to 'tests')
-rw-r--r--tests/io/internal/meson.build29
-rw-r--r--tests/io/internal/test-serialise-birthday.vala54
-rw-r--r--tests/io/internal/test-serialise-common.vala66
-rw-r--r--tests/io/internal/test-serialise-emails.vala41
-rw-r--r--tests/io/internal/test-serialise-full-name.vala42
-rw-r--r--tests/io/internal/test-serialise-nickname.vala40
-rw-r--r--tests/io/internal/test-serialise-structured-name.vala45
-rw-r--r--tests/io/internal/test-serialise-urls.vala41
-rw-r--r--tests/io/meson.build2
-rw-r--r--tests/io/vcard/meson.build32
-rw-r--r--tests/io/vcard/minimal.vcf4
-rw-r--r--tests/io/vcard/test-vcard-minimal-import.vala61
-rw-r--r--tests/meson.build6
13 files changed, 461 insertions, 2 deletions
diff --git a/tests/io/internal/meson.build b/tests/io/internal/meson.build
new file mode 100644
index 0000000..82590ef
--- /dev/null
+++ b/tests/io/internal/meson.build
@@ -0,0 +1,29 @@
+io_internal_testlib = library('io-internal-testlib',
+ files('test-serialise-common.vala'),
+ dependencies: libcontacts_dep,
+)
+
+io_internal_testlib_dep = declare_dependency(
+ link_with: io_internal_testlib,
+ include_directories: include_directories('.'),
+)
+
+io_internal_test_names = [
+ 'serialise-full-name',
+ 'serialise-structured-name',
+ 'serialise-nickname',
+ 'serialise-birthday',
+ 'serialise-emails',
+ 'serialise-urls',
+]
+
+foreach _test : io_internal_test_names
+ test_bin = executable(_test,
+ files('test-'+_test+'.vala'),
+ dependencies: [ libcontacts_dep, io_internal_testlib_dep ],
+ )
+
+ test(_test, test_bin,
+ suite: 'io-internal',
+ )
+endforeach
diff --git a/tests/io/internal/test-serialise-birthday.vala b/tests/io/internal/test-serialise-birthday.vala
new file mode 100644
index 0000000..46beef2
--- /dev/null
+++ b/tests/io/internal/test-serialise-birthday.vala
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/serialize_birthday",
+ Contacts.Tests.Io.test_serialize_birthday);
+ Test.add_func ("/io/serialize_birthday_pre_epoch",
+ Contacts.Tests.Io.test_serialize_birthday_pre_epoch);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+
+ private void test_serialize_birthday () {
+ unowned var bd_key = PersonaStore.detail_key (PersonaDetail.BIRTHDAY);
+
+ DateTime old_bd = new GLib.DateTime.utc (1992, 8, 1, 0, 0, 0);
+ var old_bd_val = Value (typeof (DateTime));
+ old_bd_val.set_boxed (old_bd);
+
+ var new_bd_val = _transform_single_value (bd_key, old_bd_val);
+ assert_true (new_bd_val.type () == typeof (DateTime));
+ assert_true (old_bd.equal ((DateTime) new_bd_val.get_boxed ()));
+ }
+
+ private void test_serialize_birthday_pre_epoch () {
+ unowned var bd_key = PersonaStore.detail_key (PersonaDetail.BIRTHDAY);
+
+ DateTime old_bd = new GLib.DateTime.utc (1961, 7, 3, 0, 0, 0);
+ var old_bd_val = Value (typeof (DateTime));
+ old_bd_val.set_boxed (old_bd);
+
+ var new_bd_val = _transform_single_value (bd_key, old_bd_val);
+ assert_true (new_bd_val.type () == typeof (DateTime));
+ assert_true (old_bd.equal ((DateTime) new_bd_val.get_boxed ()));
+ }
+}
diff --git a/tests/io/internal/test-serialise-common.vala b/tests/io/internal/test-serialise-common.vala
new file mode 100644
index 0000000..8407e2c
--- /dev/null
+++ b/tests/io/internal/test-serialise-common.vala
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+namespace Contacts.Tests.Io {
+
+ // Helper to serialize and deserialize an AbstractFieldDetails
+ public T _transform_single_afd<T> (string prop_key, T afd) {
+ Gee.Set<T> afd_set = new Gee.HashSet<T> ();
+ afd_set.add (afd);
+
+ Value val = Value (typeof (Gee.Set));
+ val.set_object (afd_set);
+
+ Value emails_value = _transform_single_value (prop_key, val);
+ var emails_set = emails_value.get_object () as Gee.Set<T>;
+ if (emails_set == null)
+ error ("GValue has null value");
+ if (emails_set.size != 1)
+ error ("Expected %d elements but got %d", 1, emails_set.size);
+
+ var deserialized_fd = Utils.get_first<T> (emails_set);
+ assert_nonnull (deserialized_fd);
+
+ return deserialized_fd;
+ }
+
+ // Helper to serialize and deserialize a single property with a GLib.Value
+ public GLib.Value _transform_single_value (string prop_key, GLib.Value val) {
+ var details = new HashTable<string, Value?> (GLib.str_hash, GLib.str_equal);
+ details.insert (prop_key, val);
+
+ // Serialize
+ Variant serialized = Contacts.Io.serialize_to_gvariant_single (details);
+ if (serialized == null)
+ error ("Couldn't serialize single-value table for property %s", prop_key);
+
+ // Deserialize
+ var details_deserialized = Contacts.Io.deserialize_gvariant_single (serialized);
+ if (details_deserialized == null)
+ error ("Couldn't deserialize details for property %s", prop_key);
+
+ if (!details_deserialized.contains (prop_key))
+ error ("Deserialized details doesn't contain value for property %s", prop_key);
+ Value? val_deserialized = details_deserialized.lookup (prop_key);
+ if (val_deserialized.type() == GLib.Type.NONE)
+ error ("Deserialized Value is unset");
+
+ return val_deserialized;
+ }
+}
diff --git a/tests/io/internal/test-serialise-emails.vala b/tests/io/internal/test-serialise-emails.vala
new file mode 100644
index 0000000..27b15ac
--- /dev/null
+++ b/tests/io/internal/test-serialise-emails.vala
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/serialize_emails",
+ Contacts.Tests.Io.test_serialize_emails);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+
+ private void test_serialize_emails () {
+ unowned var emails_key = PersonaStore.detail_key (PersonaDetail.EMAIL_ADDRESSES);
+
+ var old_fd = new EmailFieldDetails ("nielsdegraef@gmail.com");
+ var new_fd = _transform_single_afd<EmailFieldDetails> (emails_key, old_fd);
+
+ if (!(new_fd is EmailFieldDetails))
+ error ("Expected EmailFieldDetails but got %s", new_fd.get_type ().name ());
+
+ if (old_fd.value != new_fd.value)
+ error ("Expected '%s' but got '%s'", old_fd.value, new_fd.value);
+ }
+}
diff --git a/tests/io/internal/test-serialise-full-name.vala b/tests/io/internal/test-serialise-full-name.vala
new file mode 100644
index 0000000..9da8319
--- /dev/null
+++ b/tests/io/internal/test-serialise-full-name.vala
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/serialize_full_name_simple",
+ Contacts.Tests.Io.test_serialize_full_name_simple);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+
+ private void test_serialize_full_name_simple () {
+ unowned var fn_key = PersonaStore.detail_key (PersonaDetail.FULL_NAME);
+
+ string old_fn = "Niels De Graef";
+ Value old_fn_val = Value (typeof (string));
+ old_fn_val.set_string (old_fn);
+
+ var new_fn_val = _transform_single_value (fn_key, old_fn_val);
+ if (new_fn_val.type () != typeof (string))
+ error ("Expected G_TYPE_STRING but got %s", new_fn_val.type ().name ());
+ if (old_fn != new_fn_val.get_string ())
+ error ("Expected '%s' but got '%s'", old_fn, new_fn_val.get_string ());
+ }
+}
diff --git a/tests/io/internal/test-serialise-nickname.vala b/tests/io/internal/test-serialise-nickname.vala
new file mode 100644
index 0000000..649b638
--- /dev/null
+++ b/tests/io/internal/test-serialise-nickname.vala
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/serialize_nickame",
+ Contacts.Tests.Io.test_serialize_nickname);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+
+ private void test_serialize_nickname () {
+ unowned var nick_key = PersonaStore.detail_key (PersonaDetail.NICKNAME);
+
+ string old_nick = "nielsdg";
+ var old_nick_val = Value (typeof (string));
+ old_nick_val.set_string (old_nick);
+
+ var new_nick_val = _transform_single_value (nick_key, old_nick_val);
+ assert_true (new_nick_val.type () == typeof (string));
+ assert_true (old_nick == new_nick_val.get_string ());
+ }
+}
diff --git a/tests/io/internal/test-serialise-structured-name.vala b/tests/io/internal/test-serialise-structured-name.vala
new file mode 100644
index 0000000..45f2093
--- /dev/null
+++ b/tests/io/internal/test-serialise-structured-name.vala
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/serialize_structured_name_simple",
+ Contacts.Tests.Io.test_serialize_structured_name_simple);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+
+ private void test_serialize_structured_name_simple () {
+ unowned var sn_key = PersonaStore.detail_key (PersonaDetail.STRUCTURED_NAME);
+
+ var old_sn = new StructuredName.simple ("Niels", "De Graef");
+ Value old_sn_val = Value (typeof (StructuredName));
+ old_sn_val.set_object (old_sn);
+
+ var new_sn_val = _transform_single_value (sn_key, old_sn_val);
+
+ if (new_sn_val.type () != typeof (StructuredName))
+ error ("Expected FOLKS_TYPE_STRUCTURED_NAME but got %s", new_sn_val.type ().name ());
+
+ var new_sn = new_sn_val.get_object () as StructuredName;
+ if (!old_sn.equal (new_sn))
+ error ("Expected '%s' but got '%s'", old_sn.to_string (), new_sn.to_string ());
+ }
+}
diff --git a/tests/io/internal/test-serialise-urls.vala b/tests/io/internal/test-serialise-urls.vala
new file mode 100644
index 0000000..cf4cdf9
--- /dev/null
+++ b/tests/io/internal/test-serialise-urls.vala
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/serialize_urls_single",
+ Contacts.Tests.Io.test_serialize_urls_single);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+
+ private void test_serialize_urls_single () {
+ unowned var urls_key = PersonaStore.detail_key (PersonaDetail.URLS);
+
+ var old_fd = new UrlFieldDetails ("http://www.islinuxaboutchoice.com/");
+ var new_fd = _transform_single_afd<UrlFieldDetails> (urls_key, old_fd);
+
+ if (!(new_fd is UrlFieldDetails))
+ error ("Expected UrlFieldDetails but got %s", new_fd.get_type ().name ());
+
+ if (old_fd.value != new_fd.value)
+ error ("Expected '%s' but got '%s'", old_fd.value, new_fd.value);
+ }
+}
diff --git a/tests/io/meson.build b/tests/io/meson.build
new file mode 100644
index 0000000..2f34960
--- /dev/null
+++ b/tests/io/meson.build
@@ -0,0 +1,2 @@
+subdir('internal')
+subdir('vcard')
diff --git a/tests/io/vcard/meson.build b/tests/io/vcard/meson.build
new file mode 100644
index 0000000..9967815
--- /dev/null
+++ b/tests/io/vcard/meson.build
@@ -0,0 +1,32 @@
+io_vcard_files = [
+ 'minimal',
+]
+
+test_deps = [
+ gee,
+ folks,
+ libebook,
+]
+
+foreach vcard_name : io_vcard_files
+ vcf_file = meson.current_source_dir() / vcard_name + '.vcf'
+
+ # Ideally we'd do this using a preprocessor symbol or something
+ vcf_test_env = environment()
+ vcf_test_env.append('_VCF_FILE', vcf_file)
+
+ test_sources = [
+ contacts_io_sources,
+ 'test-vcard-'+vcard_name+'-import.vala',
+ ]
+
+ test_bin = executable(vcard_name,
+ test_sources,
+ dependencies: test_deps,
+ )
+
+ test(vcard_name, test_bin,
+ suite: 'io-vcard',
+ env: vcf_test_env,
+ )
+endforeach
diff --git a/tests/io/vcard/minimal.vcf b/tests/io/vcard/minimal.vcf
new file mode 100644
index 0000000..b360c5a
--- /dev/null
+++ b/tests/io/vcard/minimal.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+VERSION:3.0
+FN:Niels De Graef
+END:VCARD
diff --git a/tests/io/vcard/test-vcard-minimal-import.vala b/tests/io/vcard/test-vcard-minimal-import.vala
new file mode 100644
index 0000000..bef6596
--- /dev/null
+++ b/tests/io/vcard/test-vcard-minimal-import.vala
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+void main (string[] args) {
+ Test.init (ref args);
+ Test.add_func ("/io/test_vcard_minimal",
+ Contacts.Tests.Io.test_vcard_minimal);
+ Test.run ();
+}
+
+namespace Contacts.Tests.Io {
+ private void test_vcard_minimal () {
+ unowned var vcf_path = Environment.get_variable ("_VCF_FILE");
+ if (vcf_path == null || vcf_path == "")
+ error ("No .vcf file set as envvar. Please use the meson test suite");
+
+ var file = GLib.File.new_for_path (vcf_path);
+ if (!file.query_exists ())
+ error (".vcf file that is used as test input doesn't exist");
+
+ var parser = new Contacts.Io.VCardParser ();
+ HashTable<string, Value?>[] details_list = null;
+ try {
+ details_list = parser.parse (file.read (null));
+ } catch (Error err) {
+ error ("Error while importing: %s", err.message);
+ }
+ if (details_list == null)
+ error ("VCardParser returned null");
+
+ if (details_list.length != 1)
+ error ("VCardParser parsed %u elements instead of 1", details_list.length);
+
+ unowned var details = details_list[0];
+
+ unowned var fn_key = PersonaStore.detail_key (PersonaDetail.FULL_NAME);
+ if (!details.contains (fn_key))
+ error ("No FN value");
+
+ var fn_value = details.lookup (fn_key);
+ unowned var fn = fn_value as string;
+ if (fn != "Niels De Graef")
+ error ("Expected '%s' but got '%s'", "Niels De Graef", fn);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 92c3586..6dcfcf1 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,14 +1,16 @@
+subdir('io')
+
test_names = [
'basic-test',
]
foreach _test : test_names
test_bin = executable(_test,
- '@0@.vala'.format(_test),
+ files('@0@.vala'.format(_test)),
dependencies: libcontacts_dep,
)
test(_test, test_bin,
- suite: 'gnome-contacts',
+ suite: 'src',
)
endforeach