[folks/648811-dummy-backend-non-dbus-rebase1: 2/2] dummy: UNFINISHED work to document backend and port tests to it
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [folks/648811-dummy-backend-non-dbus-rebase1: 2/2] dummy: UNFINISHED work to document backend and port tests to it
- Date: Sun, 27 Oct 2013 18:22:23 +0000 (UTC)
commit 64c6d528666c28e291c18341236f96dafcea597b
Author: Philip Withnall <philip tecnocode co uk>
Date: Wed May 22 23:57:15 2013 +0100
dummy: UNFINISHED work to document backend and port tests to it
backends/dummy/dummy-backend-factory.vala | 2 +-
backends/dummy/lib/dummy-backend.vala | 77 ++++++++-
backends/dummy/lib/dummy-fat-persona.vala | 233 +++++++++++++++++++++++++--
backends/dummy/lib/dummy-persona-store.vala | 232 ++++++++++++++++++++++++---
backends/dummy/lib/dummy-persona.vala | 8 +
configure.ac | 1 +
tests/folks/Makefile.am | 10 ++
tests/folks/aggregation.vala | 27 ++--
tests/lib/Makefile.am | 3 +
tests/lib/test-case.vala | 58 +++++++
tests/lib/test-utils.vala | 70 ++++++++
11 files changed, 665 insertions(+), 56 deletions(-)
---
diff --git a/backends/dummy/dummy-backend-factory.vala b/backends/dummy/dummy-backend-factory.vala
index 9b7a6f6..08df1cd 100644
--- a/backends/dummy/dummy-backend-factory.vala
+++ b/backends/dummy/dummy-backend-factory.vala
@@ -43,5 +43,5 @@ public void module_init (BackendStore backend_store)
*/
public void module_finalize (BackendStore backend_store)
{
- /* TODO */
+ /* TODO: No backend_store.remove_backend() API exists. */
}
diff --git a/backends/dummy/lib/dummy-backend.vala b/backends/dummy/lib/dummy-backend.vala
index 6646649..d76463c 100644
--- a/backends/dummy/lib/dummy-backend.vala
+++ b/backends/dummy/lib/dummy-backend.vala
@@ -25,8 +25,23 @@ using Folks;
extern const string BACKEND_NAME;
/**
- * A backend which connects to EDS and creates a { link PersonaStore}
- * for each service. TODO
+ * A backend which allows { link Dummyf.PersonaStore}s and
+ * { link Dummyf.Persona}s to be programmatically created and manipulated, for
+ * the purposes of testing the core of libfolks itself.
+ *
+ * This backend is not meant to be enabled in production use. The methods on
+ * { link Dummyf.Backend} (and other classes) for programmatically manipulating
+ * the backend's state are considered internal to libfolks and are not stable.
+ *
+ * This backend maintains two sets of persona stores: the set of all persona
+ * stores, and the set of enabled persona stores (which must be a subset of the
+ * former). { link Dummyf.Backend.register_persona_stores} adds persona stores
+ * to the set of all stores. Optionally it also enables them, adding them to the
+ * set of enabled stores. The set of persona stores advertised by the backend as
+ * { link Backend.persona_stores} is the set of enabled stores. libfolks may
+ * internally enable or disable stores using
+ * { link Backend.enable_persona_store}, { link Backend.disable_persona_store}
+ * and { link Backend.set_persona_stores}.
*
* @since UNRELEASED
*/
@@ -278,13 +293,42 @@ public class Dummyf.Backend : Folks.Backend
}
}
+
+ /*
+ * All the functions below here are to be used by testing code rather than by
+ * libfolks clients. They form the interface which would normally be between
+ * the Backend and a web service or backing store of some kind.
+ */
+
+
/**
- * TODO
+ * Register and enable some { link Dummyf.PersonaStore}s.
*
+ * For each of the persona stores in ``stores``, register it with this
+ * backend. If ``enable_stores`` is ``true``, added stores will also be
+ * enabled, emitting { link Backend.persona_store_added} for each
+ * newly-enabled store. After all addition signals are emitted, a change
+ * notification for { link Backend.persona_stores} will be emitted (but only
+ * if at least one addition signal is emitted).
+ *
+ * Persona stores are identified by their { link PersonaStore.id}; if a store
+ * in ``stores`` has the same ID as a store previously registered through this
+ * method, the duplicate will be ignored (so
+ * { link Backend.persona_store_added} won't be emitted for that store).
+ *
+ * Persona stores must be instances of { link Dummyf.PersonaStore} or
+ * subclasses of it, allowing for different persona store implementations to
+ * be tested.
+ *
+ * @param stores set of persona stores to register
+ * @param enable_stores whether to automatically enable the stores
* @since UNRELEASED
*/
- public void register_persona_stores (Set<PersonaStore> stores)
+ public void register_persona_stores (Set<PersonaStore> stores,
+ bool enable_stores = true)
{
+ this.freeze_notify ();
+
foreach (var store in stores)
{
if (this._all_persona_stores.has_key (store.id))
@@ -293,17 +337,36 @@ public class Dummyf.Backend : Folks.Backend
}
this._all_persona_stores.set (store.id, store);
- this._enable_persona_store (store);
+
+ if (enable_stores == true)
+ {
+ this._enable_persona_store (store);
+ }
}
+
+ this.thaw_notify ();
}
/**
- * TODO
+ * Disable and unregister some { link Dummyf.PersonaStores}.
+ *
+ * For each of the persona stores in ``stores``, disable it (if it was
+ * enabled) and unregister it from the backend so that it cannot be re-enabled
+ * using { link Backend.enable_persona_store} or
+ * { link Backend.set_persona_stores}.
+ *
+ * { link Backend.persona_store_removed} will be emitted for all persona
+ * stores in ``stores`` which were previously enabled. After all removal
+ * signals are emitted, a change notification for
+ * { link Backend.persona_stores} will be emitted (but only if at least one
+ * removal signal is emitted).
*
* @since UNRELEASED
*/
public void unregister_persona_stores (Set<PersonaStore> stores)
{
+ this.freeze_notify ();
+
foreach (var store in stores)
{
if (!this._all_persona_stores.has_key (store.id))
@@ -314,5 +377,7 @@ public class Dummyf.Backend : Folks.Backend
this._disable_persona_store (store);
this._all_persona_stores.unset (store.id);
}
+
+ this.thaw_notify ();
}
}
diff --git a/backends/dummy/lib/dummy-fat-persona.vala b/backends/dummy/lib/dummy-fat-persona.vala
index 643e5c8..c157734 100644
--- a/backends/dummy/lib/dummy-fat-persona.vala
+++ b/backends/dummy/lib/dummy-fat-persona.vala
@@ -16,7 +16,9 @@
*
* Authors:
* Philip Withnall <philip tecnocode co uk>
- * TODO
+ * Travis Reitter <travis reitter collabora co uk>
+ * Marco Barisione <marco barisione collabora co uk>
+ * Raul Gutierrez Segales <raul gutierrez segales collabora co uk>
*/
using Folks;
@@ -668,10 +670,14 @@ public class Dummyf.FatPersona : Dummyf.Persona,
});
}
- /**
- * TODO All the functions below here are...
+
+ /*
+ * All the functions below here are to be used by testing code rather than by
+ * libfolks clients. They form the interface which would normally be between
+ * the Persona and a web service or backing store of some kind.
*/
+
private HashSet<T> _dup_to_hash_set<T> (Set<T> input_set)
{
var output_set = new HashSet<T> ();
@@ -696,6 +702,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
return output_multi_map;
}
+ /**
+ * Update persona's gender.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link GenderDetails.gender} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param gender persona's new gender
+ * @since UNRELEASED
+ */
public void update_gender (Gender gender)
{
if (this._gender != gender)
@@ -705,6 +722,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's birthday calendar event ID.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link BirthdayDetails.calendar_event_id} property. It is intended to be
+ * used for testing code which consumes this property. If the property value
+ * changes, this results in a property change notification on the persona.
+ *
+ * @param calendar_event_id persona's new birthday calendar event ID
+ * @since UNRELEASED
+ */
public void update_calendar_event_id (string? calendar_event_id)
{
if (calendar_event_id != this._calendar_event_id)
@@ -714,6 +742,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's birthday.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link BirthdayDetails.birthday} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param birthday persona's new birthday
+ * @since UNRELEASED
+ */
public void update_birthday (DateTime? birthday)
{
if ((this._birthday == null) != (birthday == null) ||
@@ -725,6 +764,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's roles.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link RoleDetails.roles} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param roles persona's new roles
+ * @since UNRELEASED
+ */
public void update_roles (Set<RoleFieldDetails> roles)
{
if (!Folks.Internal.equal_sets<RoleFieldDetails> (roles, this._roles))
@@ -735,6 +785,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's groups.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link GroupDetails.groups} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param groups persona's new groups
+ * @since UNRELEASED
+ */
public void update_groups (Set<string> groups)
{
if (!Folks.Internal.equal_sets<string> (groups, this._groups))
@@ -745,6 +806,18 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's web service addresses.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link WebServiceDetails.web_service_addresses} property. It is intended to
+ * be used for testing code which consumes this property. If the property
+ * value changes, this results in a property change notification on the
+ * persona.
+ *
+ * @param web_service_addresses persona's new web service addresses
+ * @since UNRELEASED
+ */
public void update_web_service_addresses (
MultiMap<string, WebServiceFieldDetails> web_service_addresses)
{
@@ -758,6 +831,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's e-mail addresses.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link EmailDetails.email_addresses} property. It is intended to be used
+ * for testing code which consumes this property. If the property value
+ * changes, this results in a property change notification on the persona.
+ *
+ * @param email_addresses persona's new e-mail addresses
+ * @since UNRELEASED
+ */
public void update_email_addresses (Set<EmailFieldDetails> email_addresses)
{
if (!Folks.Internal.equal_sets<EmailFieldDetails> (email_addresses,
@@ -770,6 +854,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's notes.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link NoteDetails.notes} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param notes persona's new notes
+ * @since UNRELEASED
+ */
public void update_notes (Set<NoteFieldDetails> notes)
{
if (!Folks.Internal.equal_sets<NoteFieldDetails> (notes, this._notes))
@@ -780,6 +875,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's full name.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link NameDetails.full_name} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param full_name persona's new full name
+ * @since UNRELEASED
+ */
public void update_full_name (string full_name)
{
if (this._full_name != full_name)
@@ -789,6 +895,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's nickname.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link NameDetails.nickname} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param nickname persona's new nickname
+ * @since UNRELEASED
+ */
public void update_nickname (string nickname)
{
if (this._nickname != nickname)
@@ -798,6 +915,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's structured name.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link NameDetails.structured_name} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param structured_name persona's new structured name
+ * @since UNRELEASED
+ */
public void update_structured_name (StructuredName? structured_name)
{
if (structured_name != null && !((!) structured_name).is_empty ())
@@ -812,6 +940,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's avatar.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link AvatarDetails.avatar} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param avatar persona's new avatar
+ * @since UNRELEASED
+ */
public void update_avatar (LoadableIcon? avatar)
{
if ((this._avatar == null) != (avatar == null) ||
@@ -823,6 +962,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's URIs.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link UrlDetails.urls} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param urls persona's new URIs
+ * @since UNRELEASED
+ */
public void update_urls (Set<UrlFieldDetails> urls)
{
if (!Utils.set_afd_equal (urls, this._urls))
@@ -833,6 +983,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's IM addresses.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link ImDetails.im_addresses} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param im_addresses persona's new IM addresses
+ * @since UNRELEASED
+ */
public void update_im_addresses (
MultiMap<string, ImFieldDetails> im_addresses)
{
@@ -846,16 +1007,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
- public void _update_groups (Set<string> groups)
- {
- if (!Folks.Internal.equal_sets<string> (groups, this._groups))
- {
- this._groups = this._dup_to_hash_set<string> (groups);
- this._groups_ro = this._groups.read_only_view;
- this.notify_property ("groups");
- }
- }
-
+ /**
+ * Update persona's phone numbers.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link PhoneDetails.phone_numbers} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param phone_numbers persona's new phone numbers
+ * @since UNRELEASED
+ */
public void update_phone_numbers (Set<PhoneFieldDetails> phone_numbers)
{
if (!Folks.Internal.equal_sets<PhoneFieldDetails> (phone_numbers,
@@ -868,6 +1030,18 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's postal addresses.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link PostalAddressDetails.postal_addresses} property. It is intended to
+ * be used for testing code which consumes this property. If the property
+ * value changes, this results in a property change notification on the
+ * persona.
+ *
+ * @param postal_addresses persona's new postal addresses
+ * @since UNRELEASED
+ */
public void update_postal_addresses (
Set<PostalAddressFieldDetails> postal_addresses)
{
@@ -882,6 +1056,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's local IDs.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link LocalIdDetails.local_ids} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param local_ids persona's new local IDs
+ * @since UNRELEASED
+ */
public void update_local_ids (Set<string> local_ids)
{
/* Make sure it includes our local ID. */
@@ -895,6 +1080,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's status as a favourite.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link FavouriteDetails.is_favourite} property. It is intended to be used
+ * for testing code which consumes this property. If the property value
+ * changes, this results in a property change notification on the persona.
+ *
+ * @param is_favourite persona's new status as a favourite
+ * @since UNRELEASED
+ */
public void update_is_favourite (bool is_favourite)
{
if (is_favourite != this._is_favourite)
@@ -904,6 +1100,17 @@ public class Dummyf.FatPersona : Dummyf.Persona,
}
}
+ /**
+ * Update persona's anti-links.
+ *
+ * This simulates a backing-store-side update of the persona's
+ * { link AntiLinkable.anti_links} property. It is intended to be used for
+ * testing code which consumes this property. If the property value changes,
+ * this results in a property change notification on the persona.
+ *
+ * @param anti_links persona's new anti-links
+ * @since UNRELEASED
+ */
public void update_anti_links (Set<string> anti_links)
{
if (!Folks.Internal.equal_sets<string> (anti_links, this._anti_links))
diff --git a/backends/dummy/lib/dummy-persona-store.vala b/backends/dummy/lib/dummy-persona-store.vala
index e2b6f2d..f9e9c6e 100644
--- a/backends/dummy/lib/dummy-persona-store.vala
+++ b/backends/dummy/lib/dummy-persona-store.vala
@@ -23,10 +23,14 @@ using Gee;
using GLib;
/**
- * A persona store representing a single EDS address book. TODO
+ * A persona store which allows { link Dummyf.Persona}s to be programmatically
+ * created and manipulated, for the purposes of testing the core of libfolks
+ * itself.
*
- * The persona store will contain { link Dummy.Persona}s for each contact in the
- * address book it represents.
+ * TODO: Mock functions
+ * TODO: Unstable API
+ *
+ * TODO
*
* TODO: trust_level and is_user_set_default can be set as normal properties
*
@@ -192,12 +196,12 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
}
/**
- * Create a new PersonaStore.
+ * Create a new persona store.
*
- * Create a new persona store to store the { link Persona}s for the contacts
- * in ``s``. Passing a re-used source registry to the constructor (compared to
- * the old { link Dummy.PersonaStore} constructor) saves a lot of time and
- * D-Bus round trips. TODO
+ * This store will have no personas to begin with; use
+ * { link Dummyf.PersonaStore.register_personas} to add some, then call
+ * { link Dummyf.PersonaStore.reach_quiescence} to signal the store reaching
+ * quiescence.
*
* @param id The new store's ID.
* @param display_name The new store's display name.
@@ -222,6 +226,43 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
}
/**
+ * Type of a mock function for { link PersonaStore.add_persona_from_details}.
+ *
+ * See { link Dummyf.PersonaStore.add_persona_from_details_mock}.
+ *
+ * @param persona the persona being added to the store, as constructed from
+ * the details passed to { link PersonaStore.add_persona_from_details}.
+ * @throws PersonaStoreError to be thrown from
+ * { link PersonaStore.add_persona_from_details}
+ * @since UNRELEASED
+ */
+ public delegate void AddPersonaFromDetailsMock (Persona persona)
+ throws PersonaStoreError;
+
+ /**
+ * Mock function for { link PersonaStore.add_persona_from_details}.
+ *
+ * This function is called whenever this store's
+ * { link PersonaStore.add_persona_from_details} method is called. It allows
+ * the caller to determine whether adding the given persona should fail, by
+ * throwing an error from this mock function. If no error is thrown from this
+ * function, adding the given persona will succeed. This is useful for testing
+ * error handling of calls to { link PersoneStore.add_persona_from_details}.
+ *
+ * If this is ``null``, all calls to
+ * { link PersonaStore.add_persona_from_details} will succeed.
+ *
+ * This mock function may be changed at any time; changes will take effect for
+ * the next call to { link PersonaStore.add_persona_from_details}.
+ *
+ * @since UNRELEASED
+ */
+ public unowned AddPersonaFromDetailsMock? add_persona_from_details_mock
+ {
+ get; set; default = null;
+ }
+
+ /**
* Add a new { link Persona} to the PersonaStore.
*
* Accepted keys for ``details`` are:
@@ -251,7 +292,7 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
* @since UNRELEASED
*/
public override async Folks.Persona? add_persona_from_details (
- HashTable<string, Value?> details) throws Folks.PersonaStoreError
+ HashTable<string, Value?> details) throws PersonaStoreError
{
// We have to have called prepare() beforehand.
if (!this._is_prepared)
@@ -260,8 +301,20 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
"Persona store has not yet been prepared.");
}
- /* TODO: Allow overriding the class used. */
- var persona = new Dummyf.Persona (this, "TODO", false, {});
+ /* Allow overriding the class used. */
+ var contact_id = "TODO";
+ var uid = Folks.Persona.build_uid (BACKEND_NAME, this.id, contact_id);
+ var iid = this.id + ":" + contact_id;
+
+ var persona = Object.new (this._persona_type,
+ "display-id", contact_id,
+ "uid", uid,
+ "iid", iid,
+ "store", this,
+ "is-user", false,
+ null) as Dummyf.Persona;
+ assert (persona != null);
+ persona.update_writeable_properties (this.always_writeable_properties);
var iter = HashTableIter<string, Value?> (details);
unowned string k;
@@ -388,7 +441,14 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
}*/
}
- /* TODO: How to simulate failure? */
+ /* Allow the caller to inject failures into add_persona_from_details()
+ * by providing a mock function which can throw errors as appropriate. */
+ if (this.add_persona_from_details_mock != null)
+ {
+ this.add_persona_from_details_mock (persona);
+ }
+
+ /* No simulated failure: continue adding the persona. */
this._personas.set (persona.iid, persona);
/* Notify of the new persona. */
@@ -400,6 +460,42 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
}
/**
+ * Type of a mock function for { link PersonaStore.remove_persona}.
+ *
+ * See { link Dummyf.PersonaStore.remove_persona_mock}.
+ *
+ * @param persona the persona being removed from the store
+ * @throws PersonaStoreError to be thrown from
+ * { link PersonaStore.remove_persona}
+ * @since UNRELEASED
+ */
+ public delegate void RemovePersonaMock (Persona persona)
+ throws PersonaStoreError;
+
+ /**
+ * Mock function for { link PersonaStore.remove_persona}.
+ *
+ * This function is called whenever this store's
+ * { link PersonaStore.remove_persona} method is called. It allows
+ * the caller to determine whether removing the given persona should fail, by
+ * throwing an error from this mock function. If no error is thrown from this
+ * function, removing the given persona will succeed. This is useful for
+ * testing error handling of calls to { link PersoneStore.remove_persona}.
+ *
+ * If this is ``null``, all calls to { link PersonaStore.remove_persona} will
+ * succeed.
+ *
+ * This mock function may be changed at any time; changes will take effect for
+ * the next call to { link PersonaStore.remove_persona}.
+ *
+ * @since UNRELEASED
+ */
+ public unowned RemovePersonaMock? remove_persona_mock
+ {
+ get; set; default = null;
+ }
+
+ /**
* Remove a { link Persona} from the PersonaStore.
*
* See { link Folks.PersonaStore.remove_persona}.
@@ -416,7 +512,8 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
* @since UNRELEASED
*/
public override async void remove_persona (Folks.Persona persona)
- throws Folks.PersonaStoreError
+ throws PersonaStoreError
+ requires (persona is Dummyf.Persona)
{
// We have to have called prepare() beforehand.
if (!this._is_prepared)
@@ -425,9 +522,15 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
"Persona store has not yet been prepared.");
}
- /* TODO: How to simulate failure? */
+ /* Allow the caller to inject failures into remove_persona()
+ * by providing a mock function which can throw errors as appropriate. */
+ if (this.remove_persona_mock != null)
+ {
+ this.remove_persona_mock ((Dummyf.Persona) persona);
+ }
+
Persona? _persona = this._personas.get (persona.iid);
- if (persona != null)
+ if (_persona != null)
{
this._personas.unset (persona.iid);
@@ -446,15 +549,50 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
}
/**
+ * Type of a mock function for { link PersonaStore.prepare}.
+ *
+ * See { link Dummyf.PersonaStore.prepare_mock}.
+ *
+ * @throws PersonaStoreError to be thrown from { link PersonaStore.prepare}
+ * @since UNRELEASED
+ */
+ public delegate void PrepareMock () throws PersonaStoreError;
+
+ /**
+ * Mock function for { link PersonaStore.prepare}.
+ *
+ * This function is called whenever this store's
+ * { link PersonaStore.prepare} method is called on an unprepared store. It
+ * allows the caller to determine whether preparing the store should fail, by
+ * throwing an error from this mock function. If no error is thrown from this
+ * function, preparing the store will succeed (and all future calls to
+ * { link PersonaStore.prepare} will return immediately without calling this
+ * mock function). This is useful for testing error handling of calls to
+ * { link PersoneStore.prepare}.
+ *
+ * If this is ``null``, all calls to { link PersonaStore.prepare} will
+ * succeed.
+ *
+ * This mock function may be changed at any time; changes will take effect for
+ * the next call to { link PersonaStore.prepare}.
+ *
+ * @since UNRELEASED
+ */
+ public unowned PrepareMock? prepare_mock
+ {
+ get; set; default = null;
+ }
+
+ /**
* Prepare the PersonaStore for use.
*
* See { link Folks.PersonaStore.prepare}.
*
- * @throws Folks.PersonaStoreError.STORE_OFFLINE if the EDS store is offline
+ * @throws Folks.PersonaStoreError.STORE_OFFLINE if the store is offline
* @throws Folks.PersonaStoreError.PERMISSION_DENIED if permission was denied
- * to open the EDS store
+ * to open the store
* @throws Folks.PersonaStoreError.INVALID_ARGUMENT if any other error
- * occurred in the EDS store
+ * occurred in the store
*
* @since UNRELEASED
*/
@@ -472,6 +610,13 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
{
this._prepare_pending = true;
+ /* Allow the caller to inject failures into prepare() by providing a
+ * mock function which can throw errors as appropriate. */
+ if (this.prepare_mock != null)
+ {
+ this.prepare_mock ();
+ }
+
this._is_prepared = true;
this.notify_property ("is-prepared");
@@ -490,12 +635,55 @@ public class Dummyf.PersonaStore : Folks.PersonaStore
Internal.profiling_end ("preparing Dummy.PersonaStore");
}
+
+ /*
+ * All the functions below here are to be used by testing code rather than by
+ * libfolks clients. They form the interface which would normally be between
+ * the PersonaStore and a web service or backing store of some kind.
+ */
+
+
+ private Type _persona_type = typeof (Dummyf.Persona);
+
/**
- * TODO
+ * Type of programmatically created personas.
+ *
+ * This is the type used to create new personas when
+ * { link PersonaStore.add_persona_from_details} is called. It must be a
+ * subtype of { link Dummyf.Persona}.
*
- * @param can_add_personas TODO
- * @param can_alias_personas TODO
- * @param can_remove_personas TODO
+ * This may be modified at any time, with modifications taking effect for the
+ * next call to { link PersonaStore.add_persona_from_details}.
+ *
+ * @since UNRELEASED
+ */
+ public Type persona_type
+ {
+ get { return this._persona_type; }
+ set
+ {
+ assert (value.is_a (typeof (Dummyf.Persona)));
+ if (this._persona_type != value)
+ {
+ this._persona_type = value;
+ this.notify_property ("persona-type");
+ }
+ }
+ }
+
+ /**
+ * Set capabilities of the persona store.
+ *
+ * This sets the capabilities of the store, as if they were changed on a
+ * backing store somewhere. This is intended to be used for testing code which
+ * depends on the values of { link PersonaStore.can_add_personas},
+ * { link PersonaStore.can_alias_personas} and
+ * { link PersonaStore.can_remove_personas}.
+ *
+ * @param can_add_personas whether the store can handle adding personas
+ * @param can_alias_personas whether the store can handle and update
+ * user-specified persona aliases
+ * @param can_remove_personas whether the store can handle removing personas
* @since UNRELEASED
*/
public void set_capabilities (MaybeBool can_add_personas,
diff --git a/backends/dummy/lib/dummy-persona.vala b/backends/dummy/lib/dummy-persona.vala
index 8b5f467..9634347 100644
--- a/backends/dummy/lib/dummy-persona.vala
+++ b/backends/dummy/lib/dummy-persona.vala
@@ -153,6 +153,14 @@ public class Dummyf.Persona : Folks.Persona
}
}
+
+ /*
+ * All the functions below here are to be used by testing code rather than by
+ * libfolks clients. They form the interface which would normally be between
+ * the Persona and a web service or backing store of some kind.
+ */
+
+
/**
* TODO
*
diff --git a/configure.ac b/configure.ac
index c231deb..69fc20e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -672,6 +672,7 @@ AC_CONFIG_FILES([
tests/tracker/Makefile
tests/lib/Makefile
tests/lib/folks-test-uninstalled.pc
+ tests/lib/dummy/Makefile
tests/lib/eds/Makefile
tests/lib/key-file/Makefile
tests/lib/libsocialweb/Makefile
diff --git a/tests/folks/Makefile.am b/tests/folks/Makefile.am
index 95f0493..e571941 100644
--- a/tests/folks/Makefile.am
+++ b/tests/folks/Makefile.am
@@ -8,7 +8,9 @@ AM_CPPFLAGS = \
$(TP_GLIB_CFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/folks \
+ -I$(top_srcdir)/backends/dummy/lib \
-I$(top_srcdir)/tests/lib \
+ -I$(top_srcdir)/tests/lib/dummy \
-I$(top_srcdir)/tests/lib/key-file \
-I$(top_srcdir)/tests/lib/telepathy \
-I$(top_srcdir)/tests/lib/telepathy/contactlist \
@@ -17,9 +19,11 @@ AM_CPPFLAGS = \
LDADD = \
$(top_builddir)/tests/lib/libfolks-test.la \
+ $(top_builddir)/tests/lib/dummy/libdummy-test.la \
$(top_builddir)/tests/lib/key-file/libkf-test.la \
$(top_builddir)/tests/lib/telepathy/libtpf-test.la \
$(top_builddir)/tests/lib/telepathy/contactlist/libtp-test-contactlist.la \
+ $(top_builddir)/backends/dummy/lib/libfolks-dummy.la \
$(top_builddir)/folks/libfolks.la \
$(GLIB_LIBS) \
$(GEE_LIBS) \
@@ -36,8 +40,12 @@ AM_VALAFLAGS += \
--vapidir=$(abs_builddir) \
--vapidir=$(abs_top_srcdir)/folks \
--vapidir=$(abs_top_builddir)/folks \
+ --vapidir=$(abs_top_srcdir)/backends/dummy/lib \
+ --vapidir=$(abs_top_builddir)/backends/dummy/lib \
--vapidir=$(abs_top_srcdir)/tests/lib \
--vapidir=$(abs_top_builddir)/tests/lib \
+ --vapidir=$(abs_top_srcdir)/tests/lib/dummy \
+ --vapidir=$(abs_top_builddir)/tests/lib/dummy \
--vapidir=$(abs_top_srcdir)/tests/lib/key-file \
--vapidir=$(abs_top_builddir)/tests/lib/key-file \
--vapidir=$(abs_top_srcdir)/tests/lib/telepathy \
@@ -50,9 +58,11 @@ AM_VALAFLAGS += \
--pkg folks \
--pkg folks-generics \
--pkg folks-test \
+ --pkg dummy-test \
--pkg kf-test \
--pkg tpf-test \
--pkg tp-test-contactlist \
+ --pkg folks-dummy \
-g \
$(NULL)
diff --git a/tests/folks/aggregation.vala b/tests/folks/aggregation.vala
index 2f9c2d6..4699fcb 100644
--- a/tests/folks/aggregation.vala
+++ b/tests/folks/aggregation.vala
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2013 Philip Withnall
*
* 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
@@ -15,6 +16,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Travis Reitter <travis reitter collabora co uk>
+ * Philip Withnall <philip tecnocode co uk>
*/
using Gee;
@@ -150,18 +152,10 @@ public class AggregationTests : TpfTest.MixedTestCase
Idle.add (() =>
{
- aggregator.prepare.begin ((s,r) =>
+ this.test_iid_async.begin ((s, r) =>
{
- try
- {
- aggregator.prepare.end (r);
- }
- catch (GLib.Error e1)
- {
- GLib.critical ("Failed to prepare aggregator: %s",
- e1.message);
- assert_not_reached ();
- }
+ this.test_iid_async.end (r);
+ main_loop.quit ();
});
return false;
@@ -169,9 +163,14 @@ public class AggregationTests : TpfTest.MixedTestCase
TestUtils.loop_run_with_non_fatal_timeout (main_loop, 3);
- /* We should have enumerated exactly the individuals in the set */
- assert (expected_individuals.size == 0);
- assert (expected_individuals_detailed.size == 0);
+ /* Prepare the aggregator. */
+ var individuals = yield this.individual_aggregator_prepare ();
+
+ /* Check the individuals. */
+ TestUtils.individuals_map_equals (individuals,
+ {
+ "store1:iid1,store2:iid1"
+ });
/* Clean up for the next test */
tp_backend.remove_account (account2_handle);
diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am
index e080949..d2721b9 100644
--- a/tests/lib/Makefile.am
+++ b/tests/lib/Makefile.am
@@ -1,6 +1,7 @@
# Build . first so that backends' test libraries can link to libfolks-test.la
SUBDIRS = \
. \
+ dummy \
key-file \
$(NULL)
@@ -27,6 +28,7 @@ SUBDIRS += eds
endif
DIST_SUBDIRS = \
+ dummy \
key-file \
telepathy \
eds \
@@ -38,6 +40,7 @@ noinst_LTLIBRARIES = libfolks-test.la
libfolks_test_la_SOURCES = \
haze-remove-directory.c \
+ normal-test-case.vala \
test-case.vala \
test-case-helper.c \
test-utils.vala \
diff --git a/tests/lib/test-case.vala b/tests/lib/test-case.vala
index 82b0700..0180a79 100644
--- a/tests/lib/test-case.vala
+++ b/tests/lib/test-case.vala
@@ -240,6 +240,7 @@ public abstract class Folks.TestCase : Object
this._suite.add (add_test_helper (name, test));
}
+<<<<<<< HEAD
/* implemented in test-case-helper.c */
internal extern GLib.TestCase add_test_helper (string name, TestMethod test);
@@ -262,6 +263,13 @@ public abstract class Folks.TestCase : Object
* as the last thing in their implementation.
*/
public virtual void tear_down ()
+=======
+ public virtual async void set_up ()
+ {
+ }
+
+ public virtual async void tear_down ()
+>>>>>>> dummy: UNFINISHED work to document backend and port tests to it
{
}
@@ -296,7 +304,11 @@ public abstract class Folks.TestCase : Object
}
}
+<<<<<<< HEAD
~TestCase ()
+=======
+ private class Adaptor
+>>>>>>> dummy: UNFINISHED work to document backend and port tests to it
{
this.final_tear_down ();
}
@@ -309,8 +321,28 @@ public abstract class Folks.TestCase : Object
public static void set_up ()
{
+<<<<<<< HEAD
GLib.set_printerr_handler (LogAdaptor._printerr_func_stack_trace);
Log.set_default_handler (LogAdaptor._log_func_stack_trace);
+=======
+ GLib.set_printerr_handler (Adaptor._printerr_func_stack_trace);
+ Log.set_default_handler (this._log_func_stack_trace);
+
+ var main_loop = new MainLoop ();
+
+ Idle.add (() =>
+ {
+ this._test_case.set_up.begin ((s, r) =>
+ {
+ this._test_case.set_up.end (r);
+ main_loop.quit ();
+ });
+
+ return false;
+ });
+
+ main_loop.run ();
+>>>>>>> dummy: UNFINISHED work to document backend and port tests to it
}
private static void _printerr_func_stack_trace (string? text)
@@ -340,5 +372,31 @@ public abstract class Folks.TestCase : Object
GLib.on_error_stack_trace ("libtool --mode=execute gdb");
}
}
+<<<<<<< HEAD
+=======
+
+ public void run (void* fixture)
+ {
+ this._test ();
+ }
+
+ public void tear_down (void* fixture)
+ {
+ var main_loop = new MainLoop ();
+
+ Idle.add (() =>
+ {
+ this._test_case.tear_down.begin ((s, r) =>
+ {
+ this._test_case.tear_down.end (r);
+ main_loop.quit ();
+ });
+
+ return false;
+ });
+
+ main_loop.run ();
+ }
+>>>>>>> dummy: UNFINISHED work to document backend and port tests to it
}
}
diff --git a/tests/lib/test-utils.vala b/tests/lib/test-utils.vala
index a6b855c..129bc0e 100644
--- a/tests/lib/test-utils.vala
+++ b/tests/lib/test-utils.vala
@@ -22,6 +22,7 @@
using Folks;
using GLib;
+using Gee;
public class Folks.TestUtils
{
@@ -335,4 +336,73 @@ public class Folks.TestUtils
return BuildConf.ABS_TOP_BUILDDIR + "/tests/" + filename;
}
}
+
+ /**
+ * TODO
+ *
+ * @since UNRELEASED
+ */
+ public static bool personas_set_equals (Set<Persona> actual_personas,
+ string[] expected_personas)
+ {
+ if (actual_personas.size != expected_personas.length)
+ {
+ return false;
+ }
+
+ foreach (var p in actual_personas)
+ {
+ if (!(p.uid in expected_personas))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * TODO
+ *
+ * @since UNRELEASED
+ */
+ public static bool individuals_map_equals (
+ Map<string, Individual> actual_individuals, string[] expected_individuals)
+ {
+ if (actual_individuals.size != expected_individuals.length)
+ {
+ return false;
+ }
+
+ var _actual_individuals = new HashSet<Individual> ();
+ _actual_individuals.add_all (actual_individuals.values);
+ assert (_actual_individuals.size == actual_individuals.size);
+
+ var _expected_individuals = new HashSet<string> ();
+ foreach (var i in expected_individuals)
+ {
+ _expected_individuals.add (i);
+ }
+
+ foreach (var i in _actual_individuals)
+ {
+ var actual_personas = i.personas;
+
+ foreach (var _expected_personas in _expected_individuals)
+ {
+ var expected_personas = _expected_personas.split (",");
+
+ if (TestUtils.personas_set_equals (actual_personas,
+ expected_personas) == true)
+ {
+ _expected_individuals.remove (_expected_personas);
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]