summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenato Araujo Oliveira Filho <renato.filho@canonical.com>2014-01-24 05:38:00 -0300
committerPhilip Withnall <philip@tecnocode.co.uk>2014-03-10 22:21:34 +0000
commit77d39108cc912ab3926357b5dedbe19e0a3f921a (patch)
treecce0b3c954b8dd0a2c312953b4ed652c2b598fde
parent952389b11df1e2df646fc3f2e2d0432d8e1bca2d (diff)
dummy: Add Folks.DummyPersona.update_linkable_properties()
Allow the linkable properties of a dummy persona to be edited. This includes a unit test. New API: • Folks.DummyPersona.update_linkable_properties() https://bugzilla.gnome.org/show_bug.cgi?id=722892
-rw-r--r--NEWS1
-rw-r--r--backends/dummy/lib/dummy-full-persona.vala15
-rw-r--r--backends/dummy/lib/dummy-persona.vala30
-rw-r--r--tests/dummy/Makefile.am5
-rw-r--r--tests/dummy/linkable-properties.vala275
5 files changed, 323 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 333ac05a..78fcb22d 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,7 @@ Bugs fixed:
• Bug 723540 — standalone-individuals test failing with master
• Bug 724339 — vala.m4: don't keep generated files in git
• Bug 724809 — Fail to unset contact favorite
+ • Bug 722892 — Linking personas on Dummy backend does not work
API changes:
• Add Individual.display_name
diff --git a/backends/dummy/lib/dummy-full-persona.vala b/backends/dummy/lib/dummy-full-persona.vala
index 8330abb6..f998664a 100644
--- a/backends/dummy/lib/dummy-full-persona.vala
+++ b/backends/dummy/lib/dummy-full-persona.vala
@@ -72,6 +72,16 @@ public class FolksDummy.FullPersona : FolksDummy.Persona,
PostalAddressDetails,
WebServiceDetails
{
+ private const string[] _default_linkable_properties =
+ {
+ "im-addresses",
+ "email-addresses",
+ "local-ids",
+ "web-service-addresses",
+ null /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=682698 */
+ };
+
+
/**
* Create a new ‘full’ persona.
*
@@ -88,7 +98,8 @@ public class FolksDummy.FullPersona : FolksDummy.Persona,
* @since UNRELEASED
*/
public FullPersona (PersonaStore store, string contact_id,
- bool is_user = false, string[] linkable_properties = {})
+ bool is_user = false,
+ string[] linkable_properties = {})
{
base (store, contact_id, is_user, linkable_properties);
}
@@ -104,6 +115,8 @@ public class FolksDummy.FullPersona : FolksDummy.Persona,
this._groups_ro = this._groups.read_only_view;
this._roles_ro = this._roles.read_only_view;
this._anti_links_ro = this._anti_links.read_only_view;
+ this.update_linkable_properties (
+ FullPersona._default_linkable_properties);
}
private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses =
diff --git a/backends/dummy/lib/dummy-persona.vala b/backends/dummy/lib/dummy-persona.vala
index a0d8cbdb..56679d20 100644
--- a/backends/dummy/lib/dummy-persona.vala
+++ b/backends/dummy/lib/dummy-persona.vala
@@ -96,8 +96,8 @@ public class FolksDummy.Persona : Folks.Persona
*
* @since UNRELEASED
*/
- public Persona (PersonaStore store, string contact_id, bool is_user = false,
- string[] linkable_properties = {})
+ public Persona (PersonaStore store, string contact_id,
+ bool is_user = false, string[] linkable_properties = {})
{
var uid = Folks.Persona.build_uid (BACKEND_NAME, store.id, contact_id);
var iid = store.id + ":" + contact_id;
@@ -234,6 +234,32 @@ public class FolksDummy.Persona : Folks.Persona
}
/**
+ * Update the persona’s set of linkable properties.
+ *
+ * Update the {@link Folks.Persona.linkable_properties} property to contain
+ * the given ``linkable_properties``.
+ *
+ * @param linkable_properties new set of linkable property names, in lower
+ * case, hyphenated form
+ * @since UNRELEASED
+ */
+ public void update_linkable_properties (string[] linkable_properties)
+ {
+ var new_linkable_properties = new SmallSet<string> ();
+ new_linkable_properties.add_all_array (linkable_properties);
+
+ var old_linkable_properties = new SmallSet<string> ();
+ old_linkable_properties.add_all_array (this._linkable_properties);
+
+ if (!Folks.Internal.equal_sets<string> (old_linkable_properties,
+ new_linkable_properties))
+ {
+ this._linkable_properties = linkable_properties;
+ this.notify_property ("linkable-properties");
+ }
+ }
+
+ /**
* Delay between property changes and notifications.
*
* This sets an optional delay between client code requesting a property
diff --git a/tests/dummy/Makefile.am b/tests/dummy/Makefile.am
index 90fd2d58..668dbe16 100644
--- a/tests/dummy/Makefile.am
+++ b/tests/dummy/Makefile.am
@@ -24,6 +24,7 @@ LDADD = \
TESTS = \
individual-retrieval \
add-persona \
+ linkable-properties \
$(NULL)
noinst_PROGRAMS = $(TESTS)
@@ -36,6 +37,10 @@ add_persona_SOURCES = \
add-persona.vala \
$(NULL)
+linkable_properties_SOURCES = \
+ linkable-properties.vala \
+ $(NULL)
+
-include $(top_srcdir)/git.mk
-include $(top_srcdir)/valgrind.mk
-include $(top_srcdir)/check.mk
diff --git a/tests/dummy/linkable-properties.vala b/tests/dummy/linkable-properties.vala
new file mode 100644
index 00000000..716feb56
--- /dev/null
+++ b/tests/dummy/linkable-properties.vala
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2014 Renato Araujo Oliveira Filho
+ *
+ * This library 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, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Raul Gutierrez Segales <raul.gutierrez.segales@collabora.co.uk>
+ * Travis Reitter <travis.reitter@collabora.co.uk>
+ * Renato Araujo Oliveira Filho <renato@canonical.com>
+ *
+ */
+
+using Folks;
+using Gee;
+
+public class LinkablePropertiesTests : DummyTest.TestCase
+{
+ private IndividualAggregator _aggregator;
+ private GLib.MainLoop _main_loop;
+ private bool _found_before_update;
+ private bool _found_after_update;
+
+ /* NOTE: each full name must remain unique. Likewise for email. */
+ private const string _full_name_1 = "bernie h. innocenti";
+ private const string _email_1 = "bernie@example.org";
+ private const string _phone_1 = "5551234";
+ private const string _full_name_2 = "Clyde McPoyle";
+ private const string _email_2 = "clyde@example.org";
+ private const string _phone_2 = "987654321";
+ private Individual _ind_1;
+ private Individual _ind_2;
+
+ /* In general, these tests are meant to check basic behavior so we don't need
+ * to sprinkle that throughout (and potentially revise) within unrelated tests
+ */
+ public LinkablePropertiesTests ()
+ {
+ base ("LinkableProperties");
+
+ this.add_test ("correct aggregation after linkable property change",
+ this.test_linkable_properties_aggregate_after_change);
+ }
+
+ public override void set_up ()
+ {
+ base.set_up ();
+
+ this._found_before_update = false;
+ this._found_after_update = false;
+ }
+
+ public override void configure_primary_store ()
+ {
+ base.configure_primary_store ();
+ this.dummy_persona_store.update_trust_level (PersonaStoreTrust.FULL);
+ }
+
+ private async void _add_persona (owned Gee.HashMap<string, Value?> c)
+ {
+ HashTable<string, Value?> details = new HashTable<string, Value?>
+ (str_hash, str_equal);
+
+ Value? v1 = Value (typeof (string));
+ v1.set_string (c["full_name"].get_string());
+ details.insert (Folks.PersonaStore.detail_key (PersonaDetail.FULL_NAME),
+ (owned) v1);
+
+ Value? v2 = Value (typeof (Set));
+ var emails = new HashSet<EmailFieldDetails> (
+ AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+ var email_1 = new EmailFieldDetails (c["email_1"].get_string());
+ email_1.set_parameter (AbstractFieldDetails.PARAM_TYPE,
+ AbstractFieldDetails.PARAM_TYPE_HOME);
+ emails.add (email_1);
+ v2.set_object (emails);
+ details.insert (
+ Folks.PersonaStore.detail_key (PersonaDetail.EMAIL_ADDRESSES),
+ (owned) v2);
+
+ Value? v5 = Value (typeof (Set));
+ var phones = new HashSet<PhoneFieldDetails> (
+ AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+
+ var phone_1 = new PhoneFieldDetails (c["home_phone"].get_string());
+ phone_1.set_parameter (AbstractFieldDetails.PARAM_TYPE,
+ AbstractFieldDetails.PARAM_TYPE_HOME);
+ phones.add (phone_1);
+ v5.set_object (phones);
+ details.insert (
+ Folks.PersonaStore.detail_key (PersonaDetail.PHONE_NUMBERS),
+ (owned) v5);
+
+ try
+ {
+ yield this._aggregator.add_persona_from_details (null,
+ this.dummy_persona_store, details);
+ }
+ catch (Folks.IndividualAggregatorError e)
+ {
+ GLib.warning ("[AddPersonaError] add_persona_from_details: %s\n",
+ e.message);
+ }
+ }
+
+
+ /* Check that two unaggregated Personas get aggregated after one changes its
+ * linkable property to match the other's (ie, they get linked)
+ */
+ private async void _add_personas ()
+ {
+ Gee.HashMap<string, Value?> c;
+ Value? v;
+
+ this._found_before_update = false;
+ this._found_after_update = false;
+
+ c = new Gee.HashMap<string, Value?> ();
+ v = Value (typeof (string));
+ v.set_string (_full_name_1);
+ c.set ("full_name", (owned) v);
+ v = Value (typeof (string));
+ v.set_string (_email_1);
+ c.set ("email_1", (owned) v);
+ v = Value (typeof (string));
+ v.set_string (_phone_1);
+ c.set ("home_phone", (owned) v);
+ yield this._add_persona (c);
+
+ c = new Gee.HashMap<string, Value?> ();
+ v = Value (typeof (string));
+ v.set_string (_full_name_2);
+ c.set ("full_name", (owned) v);
+ v = Value (typeof (string));
+ v.set_string (_email_2);
+ c.set ("email_1", (owned) v);
+ v = Value (typeof (string));
+ v.set_string (_phone_2);
+ c.set ("home_phone", (owned) v);
+ yield this._add_persona (c);
+ }
+
+ private void test_linkable_properties_aggregate_after_change ()
+ {
+ this._main_loop = new GLib.MainLoop (null, false);
+ test_linkable_properties_aggregate_after_change_continue.begin ();
+ TestUtils.loop_run_with_timeout (this._main_loop);
+
+ assert (this._found_before_update);
+ assert (this._found_after_update);
+ }
+
+ private async void test_linkable_properties_aggregate_after_change_continue ()
+ {
+ this._aggregator = IndividualAggregator.dup ();
+ this._aggregator.individuals_changed_detailed.connect (this._individuals_changed_aggregate_after_change_cb);
+ try
+ {
+ yield this._aggregator.prepare ();
+ }
+ catch (GLib.Error e)
+ {
+ GLib.warning ("Error when calling prepare: %s\n", e.message);
+ }
+
+ yield this._add_personas ();
+ }
+
+ private void _individuals_changed_aggregate_after_change_cb (
+ MultiMap<Individual?, Individual?> changes)
+ {
+ var added = changes.get_values ();
+
+ if (!this._found_before_update)
+ {
+ foreach (Individual i in added)
+ {
+ assert (i != null);
+
+ var name = (Folks.NameDetails) i;
+
+ if (name.full_name == _full_name_1)
+ {
+ this._ind_1 = i;
+ }
+ /* Change the second Persona's email address to match the first so
+ * they should get aggregated */
+ else if (name.full_name == _full_name_2)
+ {
+ this._ind_2 = i;
+ this._found_before_update = true;
+
+ foreach (var p in i.personas)
+ {
+ var emails = new HashSet<EmailFieldDetails> (
+ AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+ var email_1 = new EmailFieldDetails (_email_1);
+ email_1.set_parameter (AbstractFieldDetails.PARAM_TYPE,
+ AbstractFieldDetails.PARAM_TYPE_OTHER);
+ emails.add (email_1);
+ ((EmailDetails) p).email_addresses = emails;
+ }
+ }
+ }
+ }
+ else
+ {
+ Individual replaced;
+
+ if (changes.contains (this._ind_1))
+ {
+ replaced = this._ind_1;
+ }
+ else if (changes.contains (this._ind_2))
+ {
+ replaced = this._ind_2;
+ }
+ else
+ {
+ return;
+ }
+
+ var replacements = changes.get (replaced);
+ foreach (var r in replacements)
+ {
+ var phone_fd_1 = new PhoneFieldDetails (_phone_1);
+ var phone_fd_2 = new PhoneFieldDetails (_phone_1);
+ var num_equal_1 = false;
+ var num_equal_2 = false;
+
+ if (r.personas.size == 2)
+ {
+ foreach (var num in r.phone_numbers)
+ {
+ if (num.values_equal (phone_fd_1))
+ num_equal_1 = true;
+
+ if (num.values_equal (phone_fd_2))
+ num_equal_2 = true;
+ }
+
+ if (num_equal_1 && num_equal_2)
+ {
+ this._found_after_update = true;
+ this._main_loop.quit ();
+ }
+ }
+ }
+ }
+ }
+}
+
+public int main (string[] args)
+{
+ Test.init (ref args);
+
+ var tests = new LinkablePropertiesTests ();
+ tests.register ();
+ Test.run ();
+ tests.final_tear_down ();
+
+ return 0;
+}