[gupnp/gupnp-1.4] ContextFilter: Fix implementation



commit 8ab9df3a43ba1f6bfa51cf5e65ab879f16443524
Author: Jens Georg <mail jensge org>
Date:   Sun Jun 12 01:31:40 2022 +0200

    ContextFilter: Fix implementation
    
    Yeah. That was broken...

 libgupnp/gupnp-context-filter.c |  52 ++++----
 tests/meson.build               |   2 +-
 tests/test-context-filter.c     | 285 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 313 insertions(+), 26 deletions(-)
---
diff --git a/libgupnp/gupnp-context-filter.c b/libgupnp/gupnp-context-filter.c
index e23f0eb..bdfa8c4 100644
--- a/libgupnp/gupnp-context-filter.c
+++ b/libgupnp/gupnp-context-filter.c
@@ -79,9 +79,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;
@@ -105,7 +109,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);
@@ -210,8 +215,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");
+        }
 }
 
 /**
@@ -255,7 +262,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);
 }
 
 /**
@@ -307,12 +314,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");
 }
 
 /**
@@ -355,7 +370,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
  **/
@@ -414,11 +428,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);
@@ -431,17 +443,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 33637d7..a01e89c 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,4 +1,4 @@
-foreach program : ['context', 'bugs']
+foreach program : ['context', 'bugs', '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..1ac4436
--- /dev/null
+++ b/tests/test-context-filter.c
@@ -0,0 +1,285 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Jens Georg
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#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 ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]