From 542829ee81f89baf9e4fedc3f9dae063ded81eb9 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Dec 2019 15:36:34 -0500 Subject: [PATCH] Add some tests for expression binding In particular, test that expressios can deal with object == this. --- testsuite/gtk/expression.c | 305 +++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) diff --git a/testsuite/gtk/expression.c b/testsuite/gtk/expression.c index 663e0fcbaf..d8c75e527b 100644 --- a/testsuite/gtk/expression.c +++ b/testsuite/gtk/expression.c @@ -412,6 +412,304 @@ test_constant_watch_this_destroyed (void) g_clear_object (&this); g_assert_cmpint (counter, ==, 1); + + gtk_expression_unref (expr); +} + +/* Basic test of gtk_expression_bind */ +static void +test_bind (void) +{ + GtkFilter *target; + GtkFilter *source; + GtkExpression *expr; + GtkExpressionWatch *watch; + GValue value = G_VALUE_INIT; + gboolean res; + + expr = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, NULL, "search"); + + target = gtk_string_filter_new (); + gtk_string_filter_set_search (GTK_STRING_FILTER (target), "word"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (target)), ==, "word"); + + source = gtk_string_filter_new (); + gtk_string_filter_set_search (GTK_STRING_FILTER (source), "sausage"); + + watch = gtk_expression_bind (expr, target, "search", source); + gtk_expression_watch_ref (watch); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (target)), ==, "sausage"); + + gtk_string_filter_set_search (GTK_STRING_FILTER (source), "salad"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (target)), ==, "salad"); + res = gtk_expression_watch_evaluate (watch, &value); + g_assert_true (res); + g_assert_cmpstr (g_value_get_string (&value), ==, "salad"); + g_value_unset (&value); + + g_object_unref (source); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (target)), ==, "salad"); + res = gtk_expression_watch_evaluate (watch, &value); + g_assert_false (res); + g_assert_false (G_IS_VALUE (&value)); + + g_object_unref (target); + gtk_expression_watch_unref (watch); +} + +/* Another test of bind, this time we watch ourselves */ +static void +test_bind_self (void) +{ + GtkFilter *filter; + GtkExpression *expr; + + expr = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, + NULL, + "ignore-case"); + + filter = gtk_string_filter_new (); + gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "word"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter)), ==, "word"); + + gtk_expression_bind (expr, filter, "search", filter); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter)), ==, "TRUE"); + + g_object_unref (filter); +} + +/* Test bind does the right memory management if the target's + * dispose() kills the source */ +static void +test_bind_child (void) +{ + GtkFilter *filter; + GtkFilterListModel *child, *target; + GtkExpression *expr; + + expr = gtk_property_expression_new (GTK_TYPE_FILTER_LIST_MODEL, + NULL, + "filter"); + + filter = gtk_string_filter_new (); + child = gtk_filter_list_model_new_for_type (G_TYPE_OBJECT); + gtk_filter_list_model_set_filter (child, filter); + target = gtk_filter_list_model_new (G_LIST_MODEL (child), NULL); + g_object_unref (child); + g_object_unref (filter); + + gtk_expression_bind (expr, target, "filter", child); + g_assert_true (gtk_filter_list_model_get_filter (child) == gtk_filter_list_model_get_filter (target)); + + filter = gtk_string_filter_new (); + gtk_filter_list_model_set_filter (child, filter); + g_assert_true (filter == gtk_filter_list_model_get_filter (target)); + g_assert_true (gtk_filter_list_model_get_filter (child) == gtk_filter_list_model_get_filter (target)); + g_object_unref (filter); + + g_object_unref (target); +} + +/* Another test of gtk_expression_bind that exercises the subwatch code paths */ +static void +test_nested_bind (void) +{ + GtkFilter *filter; + GtkFilter *filter2; + GtkFilter *filter3; + GListModel *list; + GtkFilterListModel *filtered; + GtkExpression *expr; + GtkExpression *filter_expr; + gboolean res; + GValue value = G_VALUE_INIT; + + filter2 = gtk_string_filter_new (); + gtk_string_filter_set_search (GTK_STRING_FILTER (filter2), "sausage"); + + list = G_LIST_MODEL (g_list_store_new (G_TYPE_OBJECT)); + filtered = gtk_filter_list_model_new (list, filter2); + + filter_expr = gtk_property_expression_new (GTK_TYPE_FILTER_LIST_MODEL, + gtk_object_expression_new (G_OBJECT (filtered)), + "filter"); + expr = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, gtk_expression_ref (filter_expr), "search"); + + filter = gtk_string_filter_new (); + gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "word"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter)), ==, "word"); + + gtk_expression_bind (gtk_expression_ref (expr), filter, "search", NULL); + + gtk_string_filter_set_search (GTK_STRING_FILTER (filter2), "sausage"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter)), ==, "sausage"); + + filter3 = gtk_string_filter_new (); + gtk_string_filter_set_search (GTK_STRING_FILTER (filter3), "banana"); + gtk_filter_list_model_set_filter (filtered, filter3); + + /* check that the expressions evaluate correctly */ + res = gtk_expression_evaluate (filter_expr, NULL, &value); + g_assert_true (res); + g_assert (g_value_get_object (&value) == filter3); + g_value_unset (&value); + + res = gtk_expression_evaluate (expr, NULL, &value); + g_assert_true (res); + g_assert_cmpstr (g_value_get_string (&value), ==, "banana"); + g_value_unset (&value); + + /* and the bind too */ + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter)), ==, "banana"); + + g_object_unref (filter); + g_object_unref (filter2); + g_object_unref (filter3); + g_object_unref (filtered); + g_object_unref (list); + + gtk_expression_unref (expr); + gtk_expression_unref (filter_expr); +} + +static char * +some_cb (gpointer this, + const char *search, + gboolean ignore_case, + gpointer data) +{ + if (!search) + return NULL; + + if (ignore_case) + return g_utf8_strdown (search, -1); + else + return g_strdup (search); +} + +/* Test that things work as expected when the same object is used multiple times in an + * expression or its subexpressions. + */ +static void +test_double_bind (void) +{ + GtkStringFilter *filter1; + GtkStringFilter *filter2; + GtkExpression *expr; + GtkExpression *filter_expr; + GtkExpression *params[2]; + + filter1 = GTK_STRING_FILTER (gtk_string_filter_new ()); + filter2 = GTK_STRING_FILTER (gtk_string_filter_new ()); + + filter_expr = gtk_object_expression_new (G_OBJECT (filter1)); + + params[0] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, gtk_expression_ref (filter_expr), "search"); + params[1] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, gtk_expression_ref (filter_expr), "ignore-case"); + expr = gtk_cclosure_expression_new (G_TYPE_STRING, + NULL, + 2, params, + (GCallback)some_cb, + NULL, NULL); + + gtk_expression_bind (gtk_expression_ref (expr), filter2, "search", NULL); + + gtk_string_filter_set_search (GTK_STRING_FILTER (filter1), "Banana"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter2)), ==, "banana"); + + gtk_string_filter_set_ignore_case (GTK_STRING_FILTER (filter1), FALSE); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter2)), ==, "Banana"); + + gtk_expression_unref (expr); + gtk_expression_unref (filter_expr); + + g_object_unref (filter1); + g_object_unref (filter2); +} + +/* Test that having multiple binds on the same object works. */ +static void +test_binds (void) +{ + GtkStringFilter *filter1; + GtkStringFilter *filter2; + GtkStringFilter *filter3; + GtkExpression *expr; + GtkExpression *expr2; + GtkExpression *filter1_expr; + GtkExpression *filter2_expr; + GtkExpression *params[2]; + + filter1 = GTK_STRING_FILTER (gtk_string_filter_new ()); + filter2 = GTK_STRING_FILTER (gtk_string_filter_new ()); + filter3 = GTK_STRING_FILTER (gtk_string_filter_new ()); + + filter1_expr = gtk_object_expression_new (G_OBJECT (filter1)); + filter2_expr = gtk_object_expression_new (G_OBJECT (filter2)); + + params[0] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, gtk_expression_ref (filter1_expr), "search"); + params[1] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, gtk_expression_ref (filter2_expr), "ignore-case"); + expr = gtk_cclosure_expression_new (G_TYPE_STRING, + NULL, + 2, params, + (GCallback)some_cb, + NULL, NULL); + + expr2 = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, gtk_expression_ref (filter2_expr), "ignore-case"); + + gtk_expression_bind (gtk_expression_ref (expr), filter3, "search", NULL); + gtk_expression_bind (gtk_expression_ref (expr2), filter3, "ignore-case", NULL); + + gtk_string_filter_set_search (GTK_STRING_FILTER (filter1), "Banana"); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter3)), ==, "banana"); + g_assert_true (gtk_string_filter_get_ignore_case (GTK_STRING_FILTER (filter3))); + + gtk_string_filter_set_ignore_case (GTK_STRING_FILTER (filter2), FALSE); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter3)), ==, "Banana"); + g_assert_false (gtk_string_filter_get_ignore_case (GTK_STRING_FILTER (filter3))); + + /* invalidate the first bind */ + g_object_unref (filter1); + + gtk_string_filter_set_ignore_case (GTK_STRING_FILTER (filter2), TRUE); + g_assert_cmpstr (gtk_string_filter_get_search (GTK_STRING_FILTER (filter3)), ==, "Banana"); + g_assert_true (gtk_string_filter_get_ignore_case (GTK_STRING_FILTER (filter3))); + + gtk_expression_unref (expr); + gtk_expression_unref (expr2); + gtk_expression_unref (filter1_expr); + gtk_expression_unref (filter2_expr); + + g_object_unref (filter2); + g_object_unref (filter3); +} + +/* test that binds work ok with object expressions */ +static void +test_bind_object (void) +{ + GtkFilter *filter; + GListStore *store; + GtkFilterListModel *model; + GtkExpression *expr; + + filter = gtk_string_filter_new (); + store = g_list_store_new (G_TYPE_OBJECT); + model = gtk_filter_list_model_new (G_LIST_MODEL (store), NULL); + + expr = gtk_object_expression_new (G_OBJECT (filter)); + + gtk_expression_bind (gtk_expression_ref (expr), model, "filter", NULL); + + g_assert_true (gtk_filter_list_model_get_filter (model) == filter); + + g_object_unref (filter); + + g_assert_true (gtk_filter_list_model_get_filter (model) == filter); + + gtk_expression_unref (expr); + g_object_unref (model); + g_object_unref (store); } int @@ -429,6 +727,13 @@ main (int argc, char *argv[]) g_test_add_func ("/expression/nested-this-destroyed", test_nested_this_destroyed); g_test_add_func ("/expression/type-mismatch", test_type_mismatch); g_test_add_func ("/expression/this", test_this); + g_test_add_func ("/expression/bind", test_bind); + g_test_add_func ("/expression/bind-self", test_bind_self); + g_test_add_func ("/expression/bind-child", test_bind_child); + g_test_add_func ("/expression/nested-bind", test_nested_bind); + g_test_add_func ("/expression/double-bind", test_double_bind); + g_test_add_func ("/expression/binds", test_binds); + g_test_add_func ("/expression/bind-object", test_bind_object); return g_test_run (); }