diff options
author | Renato Araujo Oliveira Filho <renato.filho@canonical.com> | 2014-01-24 05:38:00 -0300 |
---|---|---|
committer | Philip Withnall <philip@tecnocode.co.uk> | 2014-03-10 22:21:34 +0000 |
commit | 77d39108cc912ab3926357b5dedbe19e0a3f921a (patch) | |
tree | cce0b3c954b8dd0a2c312953b4ed652c2b598fde | |
parent | 952389b11df1e2df646fc3f2e2d0432d8e1bca2d (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-- | NEWS | 1 | ||||
-rw-r--r-- | backends/dummy/lib/dummy-full-persona.vala | 15 | ||||
-rw-r--r-- | backends/dummy/lib/dummy-persona.vala | 30 | ||||
-rw-r--r-- | tests/dummy/Makefile.am | 5 | ||||
-rw-r--r-- | tests/dummy/linkable-properties.vala | 275 |
5 files changed, 323 insertions, 3 deletions
@@ -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; +} |