diff options
-rw-r--r-- | libgupnp/gupnp-context-filter.c | 52 | ||||
-rw-r--r-- | tests/meson.build | 2 | ||||
-rw-r--r-- | tests/test-context-filter.c | 287 |
3 files changed, 315 insertions, 26 deletions
diff --git a/libgupnp/gupnp-context-filter.c b/libgupnp/gupnp-context-filter.c index 4770689..4b533e1 100644 --- a/libgupnp/gupnp-context-filter.c +++ b/libgupnp/gupnp-context-filter.c @@ -99,9 +99,13 @@ gupnp_context_filter_set_property (GObject *object, case PROP_ENABLED: priv->enabled = g_value_get_boolean (value); break; - case PROP_ENTRIES: - priv->entries = g_value_get_pointer (value); - break; + case PROP_ENTRIES: { + GList *entries = g_value_get_pointer (value); + g_hash_table_remove_all (priv->entries); + for (GList *it = entries; it != NULL; it = g_list_next (it)) { + g_hash_table_add (priv->entries, g_strdup (it->data)); + } + } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -125,7 +129,8 @@ gupnp_context_filter_get_property (GObject *object, g_value_set_boolean (value, priv->enabled); break; case PROP_ENTRIES: - g_value_set_pointer (value, priv->entries); + g_value_set_pointer (value, + gupnp_context_filter_get_entries (list)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -230,8 +235,10 @@ gupnp_context_filter_set_enabled (GUPnPContextFilter *context_filter, g_return_if_fail (GUPNP_IS_CONTEXT_FILTER (context_filter)); priv = gupnp_context_filter_get_instance_private (context_filter); - priv->enabled = enable; - g_object_notify (G_OBJECT (context_filter), "enabled"); + if (priv->enabled != enable) { + priv->enabled = enable; + g_object_notify (G_OBJECT (context_filter), "enabled"); + } } /** @@ -275,7 +282,7 @@ gupnp_context_filter_is_empty (GUPnPContextFilter *context_filter) priv = gupnp_context_filter_get_instance_private (context_filter); - return (priv->entries == NULL); + return (g_hash_table_size (priv->entries) == 0); } /** @@ -327,12 +334,20 @@ gupnp_context_filter_add_entryv (GUPnPContextFilter *context_filter, gchar **entries) { gchar *const *iter = entries; + GUPnPContextFilterPrivate *priv; g_return_if_fail (GUPNP_IS_CONTEXT_FILTER (context_filter)); g_return_if_fail ((entries != NULL)); - for (; *iter != NULL; iter++) - gupnp_context_filter_add_entry (context_filter, *iter); + priv = gupnp_context_filter_get_instance_private (context_filter); + gboolean changed = FALSE; + for (; *iter != NULL; iter++) { + if (g_hash_table_add (priv->entries, g_strdup (*iter))) + changed = TRUE; + } + + if (changed) + g_object_notify (G_OBJECT (context_filter), "entries"); } /** @@ -375,7 +390,6 @@ gupnp_context_filter_remove_entry (GUPnPContextFilter *context_filter, * * Return value: (element-type utf8) (transfer container)(nullable): a #GList of entries * used to filter networks, interfaces,... or %NULL. - * Do not modify or free the list nor its elements. * * Since: 1.4.0 **/ @@ -434,11 +448,9 @@ gupnp_context_filter_check_context (GUPnPContextFilter *context_filter, GUPnPContext *context) { GSSDPClient *client; - GList *l; const char *interface; const char *host_ip; const char *network; - gboolean match = FALSE; GUPnPContextFilterPrivate *priv; g_return_val_if_fail (GUPNP_IS_CONTEXT_FILTER (context_filter), FALSE); @@ -451,17 +463,7 @@ gupnp_context_filter_check_context (GUPnPContextFilter *context_filter, host_ip = gssdp_client_get_host_ip (client); network = gssdp_client_get_network (client); - GList *head = l = g_hash_table_get_keys (priv->entries); - - while (l && !match) { - match = (interface && !strcmp (l->data, interface)) || - (host_ip && !strcmp (l->data, host_ip)) || - (network && !strcmp (l->data, network)); - - l = l->next; - } - - g_list_free (head); - - return match; + return g_hash_table_contains (priv->entries, interface) || + g_hash_table_contains (priv->entries, host_ip) || + g_hash_table_contains (priv->entries, network); } diff --git a/tests/meson.build b/tests/meson.build index deae7ba..3e656d2 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,4 +1,4 @@ -foreach program : ['context', 'bugs', 'service', 'acl', 'service-proxy'] +foreach program : ['context', 'bugs', 'service', 'acl', 'service-proxy', 'context-filter'] test( program, executable( diff --git a/tests/test-context-filter.c b/tests/test-context-filter.c new file mode 100644 index 0000000..37ba14b --- /dev/null +++ b/tests/test-context-filter.c @@ -0,0 +1,287 @@ +/* + * SPDX-FileCopyrightText: 2022 Jens Georg + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <config.h> + +#include "libgupnp/gupnp-context-filter.h" + +#include <glib-object.h> +#include <glib.h> + +void +test_context_filter_construction () +{ + // Default-created filter. No entries, disabled. + GUPnPContextFilter *filter = + g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL); + + g_assert_null (gupnp_context_filter_get_entries (filter)); + g_assert (gupnp_context_filter_is_empty (filter)); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + + g_object_unref (filter); + + // Filter that is enabled since construction + filter = + g_object_new (GUPNP_TYPE_CONTEXT_FILTER, "enabled", TRUE, NULL); + + g_assert_null (gupnp_context_filter_get_entries (filter)); + g_assert (gupnp_context_filter_is_empty (filter)); + g_assert (gupnp_context_filter_get_enabled (filter)); + + g_object_unref (filter); + + GList *entries = NULL; + entries = g_list_prepend (entries, g_strdup ("eth0")); + entries = g_list_prepend (entries, g_strdup ("::1")); + entries = g_list_prepend (entries, g_strdup ("127.0.0.1")); + entries = g_list_prepend (entries, g_strdup ("Free WiFi!")); + + filter = g_object_new (GUPNP_TYPE_CONTEXT_FILTER, + "entries", + entries, + NULL); + + g_list_free_full (entries, g_free); + + entries = gupnp_context_filter_get_entries (filter); + g_assert_cmpint (g_list_length (entries), ==, 4); + GList *it = entries; + while (it != NULL) { + g_assert (g_str_equal ("eth0", it->data) || + g_str_equal ("::1", it->data) || + g_str_equal ("127.0.0.1", it->data) || + g_str_equal ("Free WiFi!", it->data)); + it = g_list_next (it); + } + + g_list_free (entries); + + g_object_unref (filter); +} + +void +on_entry (GObject *object, GParamSpec *psec, gpointer user_data) +{ + int *count = user_data; + *count = *count + 1; +} + +void +test_context_filter_entry_management () +{ + int entry_change_count = 0; + + // Default-created filter. No entries, disabled. + GUPnPContextFilter *filter = + g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL); + + g_assert_null (gupnp_context_filter_get_entries (filter)); + g_assert (gupnp_context_filter_is_empty (filter)); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + + g_signal_connect (filter, + "notify::entries", + G_CALLBACK (on_entry), + &entry_change_count); + g_assert_cmpint (entry_change_count, ==, 0); + + entry_change_count = 0; + gupnp_context_filter_add_entry (filter, "eth0"); + + // Just adding an entry should not trigger the filter + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_false (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 1); + + GList *entries = gupnp_context_filter_get_entries (filter); + g_assert_cmpstr (entries->data, ==, "eth0"); + + g_list_free (entries); + + entry_change_count = 0; + gupnp_context_filter_add_entry (filter, "Free WiFi!"); + + // Just adding an entry should not trigger the filter + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_false (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 1); + + entries = gupnp_context_filter_get_entries (filter); + + g_assert_cmpstr (entries->data, ==, "eth0"); + + GList *it = entries; + while (it != NULL) { + g_assert (g_str_equal ("eth0", it->data) || + g_str_equal ("Free WiFi!", it->data)); + it = g_list_next (it); + } + + g_list_free (entries); + + entry_change_count = 0; + gupnp_context_filter_remove_entry (filter, "eth0"); + + // Just adding an entry should not trigger the filter + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_false (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 1); + entries = gupnp_context_filter_get_entries (filter); + + g_assert_cmpstr (entries->data, ==, "Free WiFi!"); + g_list_free (entries); + + entry_change_count = 0; + gupnp_context_filter_remove_entry (filter, "Free WiFi!"); + + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 1); + g_assert_null (gupnp_context_filter_get_entries (filter)); + + g_list_free (entries); + + { + char *entryv[] = { "eth0", "eth1", "eth2", "eth3", NULL }; + + entry_change_count = 0; + gupnp_context_filter_add_entryv (filter, entryv); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_false (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 1); + } + + // Re-adding the same entries should not cause any notification + { + char *entryv[] = { "eth0", "eth3", NULL }; + + entry_change_count = 0; + gupnp_context_filter_add_entryv (filter, entryv); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_false (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 0); + } + + entry_change_count = 0; + gupnp_context_filter_clear (filter); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_true (gupnp_context_filter_is_empty (filter)); + g_assert_cmpint (entry_change_count, ==, 1); + + g_object_unref (filter); +} + +void +on_enabled (GObject *object, GParamSpec *psec, gpointer user_data) +{ + int *count = user_data; + *count = *count + 1; +} + +void +test_context_filter_enable_disable () +{ + int enabled_count = 0; + + // Default-created filter. No entries, disabled. + GUPnPContextFilter *filter = + g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL); + + g_signal_connect (filter, + "notify::enabled", + G_CALLBACK (on_enabled), + &enabled_count); + + g_assert_false (gupnp_context_filter_get_enabled (filter)); + + enabled_count = 0; + gupnp_context_filter_set_enabled (filter, FALSE); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_cmpint (enabled_count, ==, 0); + + enabled_count = 0; + gupnp_context_filter_set_enabled (filter, TRUE); + g_assert (gupnp_context_filter_get_enabled (filter)); + g_assert_cmpint (enabled_count, ==, 1); + + enabled_count = 0; + gupnp_context_filter_set_enabled (filter, TRUE); + g_assert (gupnp_context_filter_get_enabled (filter)); + + g_assert_cmpint (enabled_count, ==, 0); + enabled_count = 0; + gupnp_context_filter_set_enabled (filter, FALSE); + g_assert_false (gupnp_context_filter_get_enabled (filter)); + g_assert_cmpint (enabled_count, ==, 1); + + g_object_unref (filter); +} + +void +test_context_filter_match () +{ + // Default-created filter. No entries, disabled. + GUPnPContextFilter *filter = + g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL); + + GUPnPContext *context = g_object_new (GUPNP_TYPE_CONTEXT, + "host-ip", + "127.0.0.1", + "interface", + "lo", + "network", + "FreeWiFi", + NULL); + + g_assert_false (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, TRUE); + g_assert_false (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, FALSE); + + g_assert (gupnp_context_filter_add_entry (filter, "FreeWiFi")); + g_assert (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, TRUE); + g_assert (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, FALSE); + gupnp_context_filter_remove_entry (filter, "FreeWiFi"); + + g_assert (gupnp_context_filter_add_entry (filter, "lo")); + g_assert (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, TRUE); + g_assert (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, FALSE); + gupnp_context_filter_remove_entry (filter, "lo"); + + g_assert (gupnp_context_filter_add_entry (filter, "127.0.0.1")); + g_assert (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, TRUE); + g_assert (gupnp_context_filter_check_context (filter, context)); + gupnp_context_filter_set_enabled (filter, FALSE); + gupnp_context_filter_remove_entry (filter, "127.0.0.1"); + + g_object_unref (context); + + g_object_unref (filter); +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/context-filter/construction", + test_context_filter_construction); + + g_test_add_func ("/context-filter/entry-management", + test_context_filter_entry_management); + + g_test_add_func ("/context-filter/enable-disable", + test_context_filter_enable_disable); + + g_test_add_func ("/context-filter/match", test_context_filter_match); + + return g_test_run (); +} |