diff options
| author | Matthew Fennell <matthew@fennell.dev> | 2025-12-27 12:40:20 +0000 |
|---|---|---|
| committer | Matthew Fennell <matthew@fennell.dev> | 2025-12-27 12:40:20 +0000 |
| commit | 5d8e439bc597159e3c9f0a8b65c0ae869dead3a8 (patch) | |
| tree | ed28aefed8add0da1c55c08fdf80b23c4346e0dc /tests | |
Import Upstream version 43.0upstream/latest
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/dummy-provider.c | 525 | ||||
| -rw-r--r-- | tests/dummy-provider.h | 41 | ||||
| -rw-r--r-- | tests/interactive/test-animation.c | 288 | ||||
| -rw-r--r-- | tests/interactive/test-colorbutton.c | 85 | ||||
| -rw-r--r-- | tests/interactive/test-filter-sort.c | 290 | ||||
| -rw-r--r-- | tests/interactive/test-star-widget.c | 53 | ||||
| -rw-r--r-- | tests/interactive/test-task-model.c | 171 | ||||
| -rw-r--r-- | tests/interactive/test-widget.c | 130 | ||||
| -rw-r--r-- | tests/meson.build | 101 | ||||
| -rw-r--r-- | tests/test-model-filter.c | 208 | ||||
| -rw-r--r-- | tests/test-model-sort.c | 143 | ||||
| -rw-r--r-- | tests/test-task-list.c | 99 | ||||
| -rw-r--r-- | tests/test-task-model.c | 67 |
13 files changed, 2201 insertions, 0 deletions
diff --git a/tests/dummy-provider.c b/tests/dummy-provider.c new file mode 100644 index 0000000..6d6041f --- /dev/null +++ b/tests/dummy-provider.c @@ -0,0 +1,525 @@ +/* dummy-provider.c + * + * Copyright 2018-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "DummyProvider" + +#include "endeavour.h" + +#include "gtd-debug.h" +#include "dummy-provider.h" + +struct _DummyProvider +{ + GtdObject parent; + + GSequence *lists; + + guint32 number_of_tasks; + guint remove_task_source_id; +}; + +static void gtd_provider_iface_init (GtdProviderInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (DummyProvider, dummy_provider, GTD_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTD_TYPE_PROVIDER, gtd_provider_iface_init)) + +enum +{ + PROP_0, + PROP_DESCRIPTION, + PROP_ENABLED, + PROP_ICON, + PROP_ID, + PROP_NAME, + PROP_PROVIDER_TYPE, + N_PROPS +}; + + +/* + * Callbacks + */ + +static gboolean +remove_task_cb (gpointer user_data) +{ + DummyProvider *self = (DummyProvider*) user_data; + + dummy_provider_randomly_remove_task (self); + + return G_SOURCE_CONTINUE; +} + + +/* + * Auxiliary methods + */ + +static GList* +sequence_to_list (GSequence *sequence) +{ + GSequenceIter *iter = NULL; + GList *list = NULL; + + for (iter = g_sequence_get_begin_iter (sequence); + !g_sequence_iter_is_end (iter); + iter = g_sequence_iter_next (iter)) + { + list = g_list_prepend (list, g_sequence_get (iter)); + } + + return g_list_reverse (list); +} + + +/* + * GtdProvider iface + */ + +static const gchar* +dummy_provider_get_id (GtdProvider *provider) +{ + return "dummy-provider"; +} + +static const gchar* +dummy_provider_get_name (GtdProvider *provider) +{ + return "Dummy Provider"; +} + +static const gchar* +dummy_provider_get_provider_type (GtdProvider *provider) +{ + return "dummy-provider"; +} + +static const gchar* +dummy_provider_get_description (GtdProvider *provider) +{ + return "Dummyest provider of the known human history"; +} + +static gboolean +dummy_provider_get_enabled (GtdProvider *provider) +{ + return TRUE; +} + +static GIcon* +dummy_provider_get_icon (GtdProvider *provider) +{ + return g_themed_icon_new ("face-monkey-symbolic"); +} +static void +dummy_provider_create_task (GtdProvider *provider, + GtdTaskList *list, + const gchar *title, + GDateTime *due_date, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ +} + +static void +dummy_provider_update_task (GtdProvider *provider, + GtdTask *task, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_debug ("Updating task '%s'", gtd_task_get_title (task)); +} + +static void +dummy_provider_remove_task (GtdProvider *provider, + GtdTask *task, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ +} + +static void +dummy_provider_create_task_list (GtdProvider *provider, + const gchar *name, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSequenceIter *iter; + DummyProvider *self; + GtdTaskList* list; + + self = DUMMY_PROVIDER (provider); + + list = gtd_task_list_new (provider); + gtd_task_list_set_name (list, name); + + iter = g_sequence_append (self->lists, list); + g_object_set_data (G_OBJECT (list), "DummyProvider::iter", iter); + + g_signal_emit_by_name (self, "list-added", list); +} + +static void +dummy_provider_update_task_list (GtdProvider *provider, + GtdTaskList *list, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_signal_emit_by_name (provider, "list-changed", list); +} + +static void +dummy_provider_remove_task_list (GtdProvider *provider, + GtdTaskList *list, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + + GSequenceIter *iter; + + iter = g_object_get_data (G_OBJECT (list), "DummyProvider::iter"); + g_sequence_remove (iter); + + g_signal_emit_by_name (provider, "list-removed", list); +} + +static GList* +dummy_provider_get_task_lists (GtdProvider *provider) +{ + DummyProvider *self = DUMMY_PROVIDER (provider); + return sequence_to_list (self->lists); +} + +static GtdTaskList* +dummy_provider_get_inbox (GtdProvider *provider) +{ + return NULL; +} + +static void +gtd_provider_iface_init (GtdProviderInterface *iface) +{ + iface->get_id = dummy_provider_get_id; + iface->get_name = dummy_provider_get_name; + iface->get_provider_type = dummy_provider_get_provider_type; + iface->get_description = dummy_provider_get_description; + iface->get_enabled = dummy_provider_get_enabled; + iface->get_icon = dummy_provider_get_icon; + iface->create_task = dummy_provider_create_task; + iface->update_task = dummy_provider_update_task; + iface->remove_task = dummy_provider_remove_task; + iface->create_task_list = dummy_provider_create_task_list; + iface->update_task_list = dummy_provider_update_task_list; + iface->remove_task_list = dummy_provider_remove_task_list; + iface->get_task_lists = dummy_provider_get_task_lists; + iface->get_inbox = dummy_provider_get_inbox; +} + + +/* + * GObject overrides + */ + +static void +dummy_provider_finalize (GObject *object) +{ + DummyProvider *self = (DummyProvider *)object; + + g_clear_pointer (&self->lists, g_sequence_free); + + G_OBJECT_CLASS (dummy_provider_parent_class)->finalize (object); +} + +static void +dummy_provider_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtdProvider *provider = GTD_PROVIDER (object); + + switch (prop_id) + { + case PROP_DESCRIPTION: + g_value_set_string (value, dummy_provider_get_description (provider)); + break; + + case PROP_ENABLED: + g_value_set_boolean (value, dummy_provider_get_enabled (provider)); + break; + + case PROP_ICON: + g_value_set_object (value, dummy_provider_get_icon (provider)); + break; + + case PROP_ID: + g_value_set_string (value, dummy_provider_get_id (provider)); + break; + + case PROP_NAME: + g_value_set_string (value, dummy_provider_get_name (provider)); + break; + + case PROP_PROVIDER_TYPE: + g_value_set_string (value, dummy_provider_get_provider_type (provider)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +dummy_provider_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +dummy_provider_class_init (DummyProviderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = dummy_provider_finalize; + object_class->get_property = dummy_provider_get_property; + object_class->set_property = dummy_provider_set_property; + + g_object_class_override_property (object_class, PROP_DESCRIPTION, "description"); + g_object_class_override_property (object_class, PROP_ENABLED, "enabled"); + g_object_class_override_property (object_class, PROP_ICON, "icon"); + g_object_class_override_property (object_class, PROP_ID, "id"); + g_object_class_override_property (object_class, PROP_NAME, "name"); + g_object_class_override_property (object_class, PROP_PROVIDER_TYPE, "provider-type"); +} + +static void +dummy_provider_init (DummyProvider *self) +{ + self->lists = g_sequence_new (g_object_unref); +} + +DummyProvider* +dummy_provider_new (void) +{ + return g_object_new (DUMMY_TYPE_PROVIDER, NULL); +} + +guint +dummy_provider_generate_task_list (DummyProvider *self) +{ + GSequenceIter *iter; + GtdTaskList *list; + guint n_generated_tasks; + gint i; + + /* + * This generates a task list with the following layout: + * + * - Task + * - Task + * - Task + * - Task + * - Task + * - Task + * - Task + * - Task + * - Task + * - Task + */ + + gtd_provider_create_task_list (GTD_PROVIDER (self), "List", NULL, NULL, NULL); + iter = g_sequence_iter_prev (g_sequence_get_end_iter (self->lists)); + list = g_sequence_get (iter); + + n_generated_tasks = 0; + + for (i = 0; i < 10; i++) + { + g_autoptr (GtdTask) task = NULL; + g_autofree gchar *title = NULL; + g_autofree gchar *uuid = NULL; + + uuid = g_uuid_string_random (); + title = g_strdup_printf ("%d", i); + + task = gtd_task_new (); + gtd_task_set_list (task, list); + gtd_object_set_uid (GTD_OBJECT (task), uuid); + gtd_task_set_title (task, title); + gtd_task_set_position (task, n_generated_tasks++); + gtd_task_list_add_task (list, task); + } + + return n_generated_tasks; +} + +guint +dummy_provider_generate_task_lists (DummyProvider *self) +{ + static guint32 task_id = 0; + guint32 n_lists; + guint32 i; + guint32 j; + + g_return_val_if_fail (DUMMY_IS_PROVIDER (self), 0); + + n_lists = g_random_int_range (2, 5); + + g_debug ("Creating %u task lists", n_lists); + + for (i = 0; i < n_lists; i++) + { + g_autofree gchar *list_name = NULL; + GSequenceIter *iter; + GtdTaskList *new_list; + guint32 n_tasks; + + list_name = g_strdup_printf ("List %u", task_id++ + 1); + gtd_provider_create_task_list (GTD_PROVIDER (self), list_name, NULL, NULL, NULL); + + /* The new list is the last one */ + iter = g_sequence_iter_prev (g_sequence_get_end_iter (self->lists)); + new_list = g_sequence_get (iter); + + /* Create a random number of stub tasks */ + n_tasks = g_random_int_range (10, 20); + + g_debug (" Creating %u tasks at list %u (%s)", n_tasks, i, list_name); + + self->number_of_tasks += n_tasks; + + for (j = 0; j < n_tasks; j++) + { + g_autofree gchar *title = NULL; + g_autofree gchar *uuid = NULL; + GtdTask *task; + + task = gtd_task_new (); + gtd_task_set_list (task, new_list); + gtd_task_set_due_date (task, NULL); + + title = g_strdup_printf ("Task %u", j + 1); + gtd_task_set_title (task, title); + + uuid = g_uuid_string_random (); + gtd_object_set_uid (GTD_OBJECT (task), uuid); + + gtd_task_list_add_task (new_list, task); + } + } + + return self->number_of_tasks; +} + +void +dummy_provider_schedule_remove_task (DummyProvider *self) +{ + g_return_if_fail (DUMMY_IS_PROVIDER (self)); + + if (self->remove_task_source_id > 0) + return; + + self->remove_task_source_id = g_timeout_add_seconds (2, remove_task_cb, self); +} + +guint +dummy_provider_randomly_remove_task (DummyProvider *self) +{ + guint32 n_lists; + guint32 i; + guint32 j; + + g_return_val_if_fail (DUMMY_IS_PROVIDER (self), 0); + + if (self->number_of_tasks == 0) + return 0; + + n_lists = g_random_int_range (1, 3); + + g_debug ("Removing tasks from %u task lists", n_lists); + + for (i = 0; i < n_lists; i++) + { + GSequenceIter *iter; + GtdTaskList *list; + guint32 list_position; + guint32 n_tasks; + guint n_list_tasks; + + n_tasks = 0; + + do + { + list_position = g_random_int_range (0, g_sequence_get_length (self->lists)); + + /* The new list is the last one */ + iter = g_sequence_get_iter_at_pos (self->lists, list_position); + list = g_sequence_get (iter); + + n_list_tasks = g_list_model_get_n_items (G_LIST_MODEL (list)); + + if (n_list_tasks == 0) + continue; + + /* Create a random number of stub tasks */ + if (n_list_tasks > 1) + n_tasks = g_random_int_range (0, g_list_model_get_n_items (G_LIST_MODEL (list))); + else + n_tasks = 1; + } + while (n_tasks == 0); + + g_debug (" Selected list was %s (%u)", gtd_task_list_get_name (list), list_position); + g_debug (" Removing %u tasks from the list", n_tasks); + + self->number_of_tasks -= n_tasks; + + for (j = 0; j < n_tasks; j++) + { + g_autoptr (GtdTask) task = NULL; + guint task_position; + + if (n_list_tasks > 1) + task_position = g_random_int_range (0, g_list_model_get_n_items (G_LIST_MODEL (list)) - 1); + else + task_position = 0; + + task = g_list_model_get_item (G_LIST_MODEL (list), task_position); + + g_debug (" Removing task %u", task_position); + + gtd_task_list_remove_task (list, task); + } + + if (self->number_of_tasks == 0) + break; + } + + return self->number_of_tasks; +} diff --git a/tests/dummy-provider.h b/tests/dummy-provider.h new file mode 100644 index 0000000..51ba8fb --- /dev/null +++ b/tests/dummy-provider.h @@ -0,0 +1,41 @@ +/* dummy-provider.h + * + * Copyright 2018 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "endeavour.h" + +G_BEGIN_DECLS + +#define DUMMY_TYPE_PROVIDER (dummy_provider_get_type()) + +G_DECLARE_FINAL_TYPE (DummyProvider, dummy_provider, DUMMY, PROVIDER, GtdObject) + +DummyProvider* dummy_provider_new (void); + +guint dummy_provider_generate_task_list (DummyProvider *self); + +guint dummy_provider_generate_task_lists (DummyProvider *self); + +void dummy_provider_schedule_remove_task (DummyProvider *self); + +guint dummy_provider_randomly_remove_task (DummyProvider *self); + +G_END_DECLS diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c new file mode 100644 index 0000000..6541551 --- /dev/null +++ b/tests/interactive/test-animation.c @@ -0,0 +1,288 @@ +/* test-widget.c + * + * Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "gtd-keyframe-transition.h" +#include "gtd-widget.h" + +static const char *css = +"translated {" +" background-image: none;" +" background-color: red;" +"}\n" +"wiggler {" +" background-image: none;" +" background-color: green;" +"}\n" +"rotated {" +" background-image: none;" +" background-color: blue;" +"}\n" +"mover {" +" background-image: none;" +" background-color: pink;" +"}\n" +; + +static const char *ui = +"<interface>" +" <object class='GtkWindow' id='window'>" +" <property name='default-width'>600</property>" +" <property name='default-height'>400</property>" +" <child>" +" <object class='GtkBox'>" +" <child>" +" <object class='GtdWidget'>" +" <property name='hexpand'>true</property>" +" <child>" +" <object class='GtdWidget'>" +" <property name='halign'>center</property>" +" <property name='valign'>center</property>" +" <child>" +" <object class='GtdWidget' id='translated'>" +" <property name='css-name'>translated</property>" +" <property name='width-request'>30</property>" +" <property name='height-request'>30</property>" +" </object>" +" </child>" +" </object>" +" </child>" +" <child>" +" <object class='GtdWidget'>" +" <property name='halign'>center</property>" +" <property name='valign'>start</property>" +" <child>" +" <object class='GtdWidget' id='wiggler'>" +" <property name='css-name'>wiggler</property>" +" <property name='translation-y'>40</property>" +" <property name='width-request'>300</property>" +" <property name='height-request'>40</property>" +" </object>" +" </child>" +" </object>" +" </child>" +" <child>" +" <object class='GtdWidget'>" +" <property name='halign'>center</property>" +" <property name='valign'>end</property>" +" <child>" +" <object class='GtdWidget' id='rotated'>" +" <property name='css-name'>rotated</property>" +" <property name='translation-y'>-80</property>" +" <property name='width-request'>40</property>" +" <property name='height-request'>40</property>" +" </object>" +" </child>" +" </object>" +" </child>" +" <child>" +" <object class='GtdWidget'>" +" <property name='halign'>center</property>" +" <property name='valign'>end</property>" +" <child>" +" <object class='GtdWidget' id='mover'>" +" <property name='css-name'>mover</property>" +" <property name='translation-x'>-200</property>" +" <property name='translation-y'>-40</property>" +" <property name='width-request'>50</property>" +" <property name='height-request'>50</property>" +" </object>" +" </child>" +" </object>" +" </child>" +" </object>" +" </child>" +" <child>" +" <object class='GtkButton' id='button'>" +" <property name='label'>Move</property>" +" <property name='valign'>start</property>" +" <property name='margin-top'>12</property>" +" <property name='margin-start'>12</property>" +" <property name='margin-end'>12</property>" +" <property name='margin-bottom'>12</property>" +" </object>" +" </child>" +" </object>" +" </child>" +" </object>" +"</interface>"; + +static gboolean pink_moved = FALSE; + +static void +animate_rotation (GtdWidget *widget) +{ + GtdTransition *rotation_z; + GtdTransition *scale_x; + GtdTransition *scale_y; + + rotation_z = gtd_property_transition_new ("rotation-z"); + gtd_transition_set_from (rotation_z, G_TYPE_FLOAT, 0.f); + gtd_transition_set_to (rotation_z, G_TYPE_FLOAT, 360.f); + gtd_timeline_set_duration (GTD_TIMELINE (rotation_z), 750); + gtd_timeline_set_repeat_count (GTD_TIMELINE (rotation_z), -1); + gtd_timeline_set_auto_reverse (GTD_TIMELINE (rotation_z), TRUE); + + scale_x = gtd_property_transition_new ("scale-x"); + gtd_transition_set_from (scale_x, G_TYPE_FLOAT, 1.f); + gtd_transition_set_to (scale_x, G_TYPE_FLOAT, 2.f); + gtd_timeline_set_duration (GTD_TIMELINE (scale_x), 750); + gtd_timeline_set_repeat_count (GTD_TIMELINE (scale_x), -1); + gtd_timeline_set_auto_reverse (GTD_TIMELINE (scale_x), TRUE); + + scale_y = gtd_property_transition_new ("scale-y"); + gtd_transition_set_from (scale_y, G_TYPE_FLOAT, 1.f); + gtd_transition_set_to (scale_y, G_TYPE_FLOAT, 2.f); + gtd_timeline_set_duration (GTD_TIMELINE (scale_y), 750); + gtd_timeline_set_repeat_count (GTD_TIMELINE (scale_y), -1); + gtd_timeline_set_auto_reverse (GTD_TIMELINE (scale_y), TRUE); + + gtd_widget_add_transition (widget, "loop-rotation-z", rotation_z); + gtd_widget_add_transition (widget, "loop-scale-x", scale_x); + gtd_widget_add_transition (widget, "loop-scale-y", scale_y); +} + +static void +animate_translation (GtdWidget *widget) +{ + GtdTransition *transition_x; + + transition_x = gtd_property_transition_new ("translation-x"); + gtd_transition_set_from (transition_x, G_TYPE_FLOAT, -200.f); + gtd_transition_set_to (transition_x, G_TYPE_FLOAT, 200.f); + gtd_timeline_set_duration (GTD_TIMELINE (transition_x), 2000); + gtd_timeline_set_repeat_count (GTD_TIMELINE (transition_x), -1); + gtd_timeline_set_auto_reverse (GTD_TIMELINE (transition_x), TRUE); + + gtd_widget_add_transition (widget, "loop-translation-x", transition_x); +} + +static void +animate_wiggle (GtdWidget *widget) +{ + GtdTransition *transition_x; + + g_message ("Adding wiggle"); + + gtd_widget_remove_all_transitions (widget); + + transition_x = gtd_keyframe_transition_new ("translation-x"); + gtd_transition_set_from (transition_x, G_TYPE_FLOAT, 0.f); + gtd_transition_set_to (transition_x, G_TYPE_FLOAT, 0.f); + gtd_timeline_set_duration (GTD_TIMELINE (transition_x), 350); + gtd_timeline_set_delay (GTD_TIMELINE (transition_x), 1000); + gtd_keyframe_transition_set (GTD_KEYFRAME_TRANSITION (transition_x), + G_TYPE_FLOAT, + 5, + 0.20, -15.f, GTD_EASE_OUT_QUAD, + 0.40, 15.f, GTD_EASE_LINEAR, + 0.60, -15.f, GTD_EASE_LINEAR, + 0.80, 15.f, GTD_EASE_LINEAR, + 1.00, 0.f, GTD_EASE_IN_QUAD); + + gtd_widget_add_transition (widget, "wiggle", transition_x); + + g_signal_connect_swapped (transition_x, + "completed", + G_CALLBACK (animate_wiggle), + widget); +} + +static void +move_pink_cb (GtkButton *button, + GtdWidget *widget) +{ + GtdTransition *rotation_y; + + gtd_widget_remove_all_transitions (widget); + + rotation_y = gtd_property_transition_new ("rotation-y"); + gtd_transition_set_from (rotation_y, G_TYPE_FLOAT, 0.f); + gtd_transition_set_to (rotation_y, G_TYPE_FLOAT, 360.f); + gtd_timeline_set_duration (GTD_TIMELINE (rotation_y), 500); + gtd_timeline_set_repeat_count (GTD_TIMELINE (rotation_y), 3); + + gtd_widget_save_easing_state (widget); + gtd_widget_set_easing_duration (widget, 2000); + gtd_widget_set_easing_mode (widget, GTD_EASE_LINEAR); + gtd_widget_set_translation (widget, pink_moved ? -200.f : 200.f, -40.f, 0.f); + gtd_widget_restore_easing_state (widget); + + gtd_widget_add_transition (widget, "loop-rotation-y", rotation_y); + + pink_moved = !pink_moved; +} + +static GtkWidget * +create_ui (void) +{ + g_autoptr (GtkBuilder) builder = NULL; + g_autoptr (GError) error = NULL; + GtkWidget *win; + + g_type_ensure (GTD_TYPE_WIDGET); + + builder = gtk_builder_new (); + if (!gtk_builder_add_from_string (builder, ui, -1, &error)) + { + g_warning ("%s", error->message); + return NULL; + } + + win = (GtkWidget *)gtk_builder_get_object (builder, "window"); + g_object_ref (win); + + animate_rotation ((GtdWidget *)gtk_builder_get_object (builder, "rotated")); + animate_translation ((GtdWidget *)gtk_builder_get_object (builder, "translated")); + animate_wiggle ((GtdWidget *)gtk_builder_get_object (builder, "wiggler")); + + g_signal_connect (gtk_builder_get_object (builder, "button"), + "clicked", + G_CALLBACK (move_pink_cb), + gtk_builder_get_object (builder, "mover")); + + return win; +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_autoptr (GtkCssProvider) css_provider = NULL; + GtkWindow *window; + + g_set_prgname ("test-colorbutton"); + g_set_application_name ("Endeavour | Widget Test"); + + gtk_init (); + + css_provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (css_provider, css, -1); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + window = GTK_WINDOW (create_ui ()); + gtk_window_present (window); + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/tests/interactive/test-colorbutton.c b/tests/interactive/test-colorbutton.c new file mode 100644 index 0000000..065c978 --- /dev/null +++ b/tests/interactive/test-colorbutton.c @@ -0,0 +1,85 @@ +/* test-colorbutton.c + * + * Copyright 2018-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "gtd-color-button.h" + +static const gchar * const colors[] = +{ + "#ffffff", + "#dddddd", + "#ababab", + "#fafa00", + "#888888", + "#333333", + "#000000", + "#96ff11", + "#03fa95", +}; + +gint +main (gint argc, + gchar *argv[]) +{ + GtkWindow *window = NULL; + GtkWidget *grid = NULL; + guint columns; + guint i; + + g_set_prgname ("test-colorbutton"); + g_set_application_name ("Endeavour | Color Button Test"); + + gtk_init (); + + grid = g_object_new (GTK_TYPE_GRID, + "row-homogeneous", TRUE, + "column-homogeneous", TRUE, + NULL); + + columns = ceil (sqrt (G_N_ELEMENTS (colors))); + + for (i = 0; i < G_N_ELEMENTS (colors); i++) + { + GtkWidget *color_button = NULL; + GdkRGBA color; + + gdk_rgba_parse (&color, colors[i]); + + color_button = g_object_new (GTD_TYPE_COLOR_BUTTON, + "color", &color, + NULL); + + gtk_grid_attach (GTK_GRID (grid), + color_button, + i % columns, + i / columns, + 1, + 1); + } + + window = GTK_WINDOW (gtk_window_new ()); + gtk_window_set_child (window, grid); + gtk_window_present (window); + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} + diff --git a/tests/interactive/test-filter-sort.c b/tests/interactive/test-filter-sort.c new file mode 100644 index 0000000..a356e3c --- /dev/null +++ b/tests/interactive/test-filter-sort.c @@ -0,0 +1,290 @@ +/* test-filter-sort.c + * + * Copyright 2018-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#include <gtk/gtk.h> + +#include "core/gtd-log.h" +#include "models/gtd-list-model-filter.h" +#include "models/gtd-list-model-sort.h" +#include "models/gtd-task-model.h" +#include "models/gtd-task-model-private.h" +#include "dummy-provider.h" +#include "gtd-manager.h" +#include "gtd-manager-protected.h" +#include "gtd-provider.h" +#include "gtd-task.h" +#include "gtd-task-list.h" +#include "gtd-utils.h" + + +/* + * Auxiliary methods + */ + +static GtkWidget* +create_bold_label_for_task_row (GtkListBoxRow *row) +{ + g_autofree gchar *markup = NULL; + GtdTask *task; + + task = g_object_get_data (G_OBJECT (row), "task"); + markup = g_strdup_printf ("<big><b>%s</b></big>", gtd_task_list_get_name (gtd_task_get_list (task))); + + return g_object_new (GTK_TYPE_LABEL, + "margin", 6, + "margin-top", 18, + "use-markup", TRUE, + "label", markup, + "xalign", 0.0, + NULL); +} + +static GtkWidget* +create_label_for_string (const gchar *string) +{ + return g_object_new (GTK_TYPE_LABEL, + "label", string, + "hexpand", TRUE, + "xalign", 0.0, + "margin", 6, + "margin-start", 18, + NULL); +} + + +/* + * Callbacks + */ + +static void +header_func (GtkListBoxRow *row, + GtkListBoxRow *before, + gpointer user_data) +{ + GtkWidget *header = NULL; + + if (!before) + { + header = create_bold_label_for_task_row (row); + } + else + { + GtdTask *before_task; + GtdTask *task; + + before_task = g_object_get_data (G_OBJECT (before), "task"); + task = g_object_get_data (G_OBJECT (row), "task"); + + if (gtd_task_get_list (task) != gtd_task_get_list (before_task)) + header = create_bold_label_for_task_row (row); + } + + gtk_list_box_row_set_header (row, header); +} + +static gboolean +filter_func (GObject *item, + gpointer user_data) +{ + g_autofree gchar *normalized_entry_text = NULL; + g_autofree gchar *normalized_task_name = NULL; + GtkEntry *entry; + GtdTask *task; + + task = (GtdTask*) item; + entry = (GtkEntry*) user_data; + + normalized_entry_text = gtd_normalize_casefold_and_unaccent (gtk_editable_get_text (GTK_EDITABLE (entry))); + normalized_task_name = gtd_normalize_casefold_and_unaccent (gtd_task_get_title (task)); + + return strstr (normalized_task_name, normalized_entry_text) != NULL; +} + +static GtkWidget* +create_task_cb (gpointer item, + gpointer user_data) +{ + GtkWidget *row; + GtkWidget *box; + GtdTask *task; + + task = item; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16); + + gtk_box_append (GTK_BOX (box), create_label_for_string (gtd_task_get_title (task))); + + row = gtk_list_box_row_new (); + gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box); + + g_object_set_data (G_OBJECT (row), "task", task); + + return row; +} + +static gint +sort_func (GObject *a, + GObject *b, + gpointer user_data) +{ + GtkCheckButton *check; + GtdTask *task_a; + GtdTask *task_b; + + check = (GtkCheckButton*) user_data; + + if (gtk_check_button_get_active (check)) + { + task_a = GTD_TASK (a); + task_b = GTD_TASK (b); + } + else + { + task_a = GTD_TASK (b); + task_b = GTD_TASK (a); + } + + if (gtd_task_get_list (task_a) == gtd_task_get_list (task_b)) + { + return gtd_task_compare (task_b, task_a); + } + else + { + GtdTaskList *list_a = gtd_task_get_list (task_a); + GtdTaskList *list_b = gtd_task_get_list (task_b); + + return g_strcmp0 (gtd_task_list_get_name (list_b), gtd_task_list_get_name (list_a)); + } +} + +static void +on_check_active_changed_cb (GtkCheckButton *check, + GParamSpec *pspec, + GtdListModelSort *sort) +{ + gtd_list_model_sort_invalidate (sort); +} + +static void +on_remove_button_clicked_cb (GtkButton *button, + DummyProvider *provider) +{ + dummy_provider_randomly_remove_task (provider); +} + +static void +on_search_text_changed_cb (GtkEntry *entry, + GParamSpec *pspec, + GtdListModelFilter *filter) +{ + gtd_list_model_filter_invalidate (filter); +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_autoptr (GtdListModelFilter) filter = NULL; + g_autoptr (GtdListModelSort) sort = NULL; + g_autoptr (DummyProvider) dummy_provider = NULL; + GtdTaskModel *model = NULL; + GtkWidget *scrolledwindow = NULL; + GtkWidget *search_entry = NULL; + GtkWindow *window = NULL; + GtkWidget *listbox = NULL; + GtkWidget *button = NULL; + GtkWidget *check = NULL; + GtkWidget *hbox = NULL; + GtkWidget *vbox = NULL; + + g_set_prgname ("test-filter-sort"); + g_set_application_name ("Endeavour | Filter & Sort Test"); + + gtk_init (); + gtd_log_init (); + + /* Create a DumbProvider and pre-populate it */ + dummy_provider = dummy_provider_new (); + dummy_provider_generate_task_lists (dummy_provider); + dummy_provider_generate_task_lists (dummy_provider); + gtd_manager_add_provider (gtd_manager_get_default (), GTD_PROVIDER (dummy_provider)); + + /* Models */ + model = _gtd_task_model_new (gtd_manager_get_default ()); + filter = gtd_list_model_filter_new (G_LIST_MODEL (model)); + sort = gtd_list_model_sort_new (G_LIST_MODEL (filter)); + + /* Listbox */ + listbox = gtk_list_box_new (); + gtk_list_box_bind_model (GTK_LIST_BOX (listbox), + G_LIST_MODEL (sort), + create_task_cb, + NULL, + NULL); + + gtk_list_box_set_header_func (GTK_LIST_BOX (listbox), header_func, NULL, NULL); + + /* Scrolled window */ + scrolledwindow = g_object_new (GTK_TYPE_SCROLLED_WINDOW, + "propagate-natural-height", TRUE, + "max-content-height", 600, + "hscrollbar-policy", GTK_POLICY_NEVER, + NULL); + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), listbox); + + /* Search entry */ + search_entry = gtk_search_entry_new (); + gtd_list_model_filter_set_filter_func (filter, filter_func, search_entry, NULL); + + g_signal_connect_object (search_entry, "notify::text", G_CALLBACK (on_search_text_changed_cb), filter, 0); + + /* Reverse order checkbox */ + check = gtk_check_button_new_with_label ("Reverse Order"); + gtd_list_model_sort_set_sort_func (sort, sort_func, check, NULL); + + g_signal_connect_object (check, "notify::active", G_CALLBACK (on_check_active_changed_cb), sort, 0); + + /* Remove Tasks button */ + button = gtk_button_new_with_label ("Randomly Remove Tasks"); + g_signal_connect_object (button, "clicked", G_CALLBACK (on_remove_button_clicked_cb), dummy_provider, 0); + + /* Horizontal box */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_box_append (GTK_BOX (hbox), search_entry); + gtk_box_append (GTK_BOX (hbox), check); + gtk_box_append (GTK_BOX (hbox), button); + + /* Box */ + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_box_append (GTK_BOX (vbox), hbox); + gtk_box_append (GTK_BOX (vbox), scrolledwindow); + + /* Window */ + window = GTK_WINDOW (gtk_window_new ()); + gtk_window_set_default_size (window, 800, 600); + gtk_window_set_child (GTK_WINDOW (window), vbox); + gtk_window_present (window); + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/tests/interactive/test-star-widget.c b/tests/interactive/test-star-widget.c new file mode 100644 index 0000000..cfb102c --- /dev/null +++ b/tests/interactive/test-star-widget.c @@ -0,0 +1,53 @@ +/* test-star-widget.c + * + * Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#include <gtk/gtk.h> + +#include "gtd-log.h" +#include "gtd-star-widget.h" + +gint +main (gint argc, + gchar *argv[]) +{ + GtkWidget *start_widget = NULL; + GtkWindow *window = NULL; + + g_set_prgname ("test-star-widget"); + g_set_application_name ("Endeavour | Star Widget"); + + gtk_init (); + gtd_log_init (); + + /* Box */ + start_widget = gtd_star_widget_new (); + + /* Window */ + window = GTK_WINDOW (gtk_window_new ()); + gtk_window_set_default_size (window, 200, 150); + gtk_window_set_child (window, start_widget); + gtk_window_present (window); + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/tests/interactive/test-task-model.c b/tests/interactive/test-task-model.c new file mode 100644 index 0000000..aa61ba9 --- /dev/null +++ b/tests/interactive/test-task-model.c @@ -0,0 +1,171 @@ +/* test-task-model.c + * + * Copyright 2018-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <gtk/gtk.h> + +#include "models/gtd-task-model.h" +#include "models/gtd-task-model-private.h" +#include "dummy-provider.h" +#include "gtd-log.h" +#include "gtd-manager.h" +#include "gtd-manager-protected.h" +#include "gtd-provider.h" +#include "gtd-task.h" +#include "gtd-task-list.h" + +static GtkWidget* +create_bold_label_for_task_row (GtkListBoxRow *row) +{ + g_autofree gchar *markup = NULL; + GtdTask *task; + + task = g_object_get_data (G_OBJECT (row), "task"); + markup = g_strdup_printf ("<big><b>%s</b></big>", gtd_task_list_get_name (gtd_task_get_list (task))); + + return g_object_new (GTK_TYPE_LABEL, + "margin", 6, + "margin-top", 18, + "use-markup", TRUE, + "label", markup, + "xalign", 0.0, + NULL); +} + +static void +header_func (GtkListBoxRow *row, + GtkListBoxRow *before, + gpointer user_data) +{ + GtkWidget *header = NULL; + + if (!before) + { + header = create_bold_label_for_task_row (row); + } + else + { + GtdTask *before_task; + GtdTask *task; + + before_task = g_object_get_data (G_OBJECT (before), "task"); + task = g_object_get_data (G_OBJECT (row), "task"); + + if (gtd_task_get_list (task) != gtd_task_get_list (before_task)) + header = create_bold_label_for_task_row (row); + } + + gtk_list_box_row_set_header (row, header); +} + +static GtkWidget* +create_label_for_string (const gchar *string) +{ + return g_object_new (GTK_TYPE_LABEL, + "label", string, + "hexpand", TRUE, + "xalign", 0.0, + "margin", 6, + "margin-start", 18, + NULL); +} + +static GtkWidget* +create_task_cb (gpointer item, + gpointer user_data) +{ + GtkWidget *row; + GtkWidget *box; + GtdTask *task; + + task = item; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16); + + gtk_box_append (GTK_BOX (box), create_label_for_string (gtd_task_get_title (task))); + + row = gtk_list_box_row_new (); + gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box); + + g_object_set_data (G_OBJECT (row), "task", task); + + return row; +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_autoptr (DummyProvider) dummy_provider = NULL; + GtdTaskModel *model = NULL; + GtkWidget *scrolledwindow = NULL; + GtkWindow *window = NULL; + GtkWidget *listbox = NULL; + + g_set_prgname ("test-task-model"); + g_set_application_name ("Endeavour | Task Model Test"); + + gtk_init (); + gtd_log_init (); + + /* Create a DumbProvider and pre-populate it */ + dummy_provider = dummy_provider_new (); + dummy_provider_generate_task_lists (dummy_provider); + + /* Inject a dumb fake provider */ + gtd_manager_add_provider (gtd_manager_get_default (), GTD_PROVIDER (dummy_provider)); + + /* Now create the model - the initial providers must be there already */ + model = _gtd_task_model_new (gtd_manager_get_default ()); + + /* Listbox */ + listbox = gtk_list_box_new (); + gtk_list_box_bind_model (GTK_LIST_BOX (listbox), + G_LIST_MODEL (model), + create_task_cb, + NULL, + NULL); + + gtk_list_box_set_header_func (GTK_LIST_BOX (listbox), header_func, NULL, NULL); + + /* Scrolled window */ + scrolledwindow = g_object_new (GTK_TYPE_SCROLLED_WINDOW, + "propagate-natural-height", TRUE, + "max-content-height", 600, + "hscrollbar-policy", GTK_POLICY_NEVER, + NULL); + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), listbox); + + /* Window */ + window = GTK_WINDOW (gtk_window_new ()); + gtk_window_set_default_size (window, 800, 600); + gtk_window_set_child (GTK_WINDOW (window), scrolledwindow); + gtk_window_present (window); + + /* Now, generate more tasks and lists after injecting to the manager */ + dummy_provider_generate_task_lists (dummy_provider); + + /* Schedule a live removal of tasks */ + dummy_provider_schedule_remove_task (dummy_provider); + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/tests/interactive/test-widget.c b/tests/interactive/test-widget.c new file mode 100644 index 0000000..32c1d2d --- /dev/null +++ b/tests/interactive/test-widget.c @@ -0,0 +1,130 @@ +/* test-widget.c + * + * Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "gtd-widget.h" + +static const char *css = +"translated {" +" background-image: none;" +" background-color: red;" +"}\n" +"scaled {" +" background-image: none;" +" background-color: green;" +"}\n" +"rotated {" +" background-image: none;" +" background-color: blue;" +"}\n" +; + +static const char *ui = +"<interface>" +" <object class='GtkWindow' id='window'>" +" <property name='default-width'>400</property>" +" <property name='default-height'>300</property>" +" <child>" +" <object class='GtdWidget'>" +" <child>" +" <object class='GtdWidget' id='translated'>" +" <property name='css-name'>translated</property>" +" <property name='translation-x'>30.0</property>" +" <property name='translation-y'>15.0</property>" +" <property name='translation-z'>0.0</property>" +" <property name='valign'>start</property>" +" <property name='width-request'>30</property>" +" <property name='height-request'>30</property>" +" </object>" +" </child>" +" <child>" +" <object class='GtdWidget' id='scaled'>" +" <property name='css-name'>scaled</property>" +" <property name='scale-x'>0.75</property>" +" <property name='scale-y'>1.25</property>" +" <property name='scale-z'>1.0</property>" +" <property name='valign'>center</property>" +" <property name='width-request'>30</property>" +" <property name='height-request'>30</property>" +" </object>" +" </child>" +" <child>" +" <object class='GtdWidget' id='rotated'>" +" <property name='css-name'>rotated</property>" +" <property name='rotation-x'>30.0</property>" +" <property name='rotation-y'>-15.0</property>" +" <property name='rotation-z'>0</property>" +" <property name='valign'>end</property>" +" <property name='width-request'>30</property>" +" <property name='height-request'>30</property>" +" </object>" +" </child>" +" </object>" +" </child>" +" </object>" +"</interface>"; + +static GtkWidget * +create_ui (void) +{ + g_autoptr (GtkBuilder) builder = NULL; + g_autoptr (GError) error = NULL; + GtkWidget *win; + + g_type_ensure (GTD_TYPE_WIDGET); + + builder = gtk_builder_new (); + if (!gtk_builder_add_from_string (builder, ui, -1, &error)) + { + g_warning ("%s", error->message); + return NULL; + } + + win = (GtkWidget *)gtk_builder_get_object (builder, "window"); + g_object_ref (win); + + return win; +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_autoptr (GtkCssProvider) css_provider = NULL; + GtkWindow *window; + + g_set_prgname ("test-colorbutton"); + g_set_application_name ("Endeavour | Widget Test"); + + gtk_init (); + + css_provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (css_provider, css, -1); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + window = GTK_WINDOW (create_ui ()); + gtk_window_present (window); + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..6ebebe3 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,101 @@ +################# +# Tests Library # +################# + +sources = files( + 'dummy-provider.c', +) + +tests_incs = [ + include_directories('../src'), + include_directories('.'), + incs, +] + +libgtd_tests = static_library( + 'gtd_tests', + sources : sources, + include_directories : tests_incs, + dependencies : endeavour_deps, + c_args : cflags, +) + +tests_libs = [ + libgtd, + libgtd_tests, +] + + +################ +# Static tests # +################ + +static_test_env = [ + 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), + 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), + 'G_DEBUG=gc-friendly', + 'GSETTINGS_BACKEND=memory', + 'GSETTINGS_SCHEMA_DIR=@0@'.format(join_paths(meson.project_build_root(),'data')), + 'PYTHONDONTWRITEBYTECODE=yes', + 'MALLOC_CHECK_=2', + 'MALLOC_PERTURB_=$((${RANDOM:-256} % 256))', +] + +static_test_cflags = [ + '-DTEST_DATA_DIR="@0@/data"'.format(meson.current_source_dir()), +] + +static_tests = [ + 'test-model-filter', + 'test-model-sort', + 'test-task-list', + 'test-task-model', +] + +foreach static_test : static_tests + + source = ['@0@.c'.format(static_test)] + + static_test_program = executable( + static_test, + source, + c_args : static_test_cflags, + dependencies : endeavour_deps, + pie : true, + link_with : tests_libs, + include_directories : tests_incs, + ) + + test(static_test, static_test_program, env: static_test_env) +endforeach + + + +##################### +# Interactive tests # +##################### + +interactive_tests = [ + 'test-animation', + 'test-colorbutton', + 'test-filter-sort', + 'test-star-widget', + 'test-task-model', + 'test-widget', +] + +foreach interactive_test : interactive_tests + + interactive_test_name = 'interactive-@0@'.format(interactive_test) + + source = ['interactive/@0@.c'.format(interactive_test)] + + interactive_test_program = executable( + interactive_test_name, + source, + include_directories: tests_incs, + dependencies: endeavour_deps, + c_args: cflags, + link_with: tests_libs, + ) +endforeach diff --git a/tests/test-model-filter.c b/tests/test-model-filter.c new file mode 100644 index 0000000..025b9e3 --- /dev/null +++ b/tests/test-model-filter.c @@ -0,0 +1,208 @@ +#include "models/gtd-list-model-filter.h" +#include <math.h> +#include <string.h> + +#define TEST_TYPE_ITEM (test_item_get_type()) + +struct _TestItem +{ + GObject p; + guint n; +}; + +G_DECLARE_FINAL_TYPE (TestItem, test_item, TEST, ITEM, GObject) +G_DEFINE_TYPE (TestItem, test_item, G_TYPE_OBJECT) + +static void +test_item_class_init (TestItemClass *klass) +{ +} + +static void +test_item_init (TestItem *self) +{ +} + +static TestItem * +test_item_new (guint n) +{ + TestItem *item; + + item = g_object_new (TEST_TYPE_ITEM, NULL); + item->n = n; + + return item; +} + +static gboolean +filter_func1 (GObject *object, + gpointer user_data) +{ + return (TEST_ITEM (object)->n & 1) == 0; +} + +static gboolean +filter_func2 (GObject *object, + gpointer user_data) +{ + return (TEST_ITEM (object)->n & 1) == 1; +} + +static void +test_basic (void) +{ + GListStore *model; + GtdListModelFilter *filter; + TestItem *item; + guint i; + + model = g_list_store_new (TEST_TYPE_ITEM); + g_assert (model); + + filter = gtd_list_model_filter_new (G_LIST_MODEL (model)); + g_assert (filter); + + /* Test requesting past boundary */ + g_assert_null (g_list_model_get_item (G_LIST_MODEL (filter), 0)); + g_assert_null (g_list_model_get_item (G_LIST_MODEL (filter), 1)); + + for (i = 0; i < 1000; i++) + { + g_autoptr (TestItem) val = test_item_new (i); + + g_list_store_append (model, val); + } + + /* Test requesting past boundary */ + g_assert_null (g_list_model_get_item (G_LIST_MODEL (filter), 1000)); + + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + gtd_list_model_filter_set_filter_func (filter, filter_func1, NULL, NULL); + g_assert_cmpint (500, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + for (i = 0; i < 500; i++) + { + g_autoptr (TestItem) ele = g_list_model_get_item (G_LIST_MODEL (filter), i); + + g_assert_nonnull (ele); + g_assert (TEST_IS_ITEM (ele)); + g_assert (filter_func1 (G_OBJECT (ele), NULL)); + + /* filter_func1 filters odd numbers out. The even numbers that + * weren't filtered should keep their order. + */ + g_assert (ele->n == i * 2); + } + + for (i = 0; i < 1000; i += 2) + g_list_store_remove (model, 998 - i); + + g_assert_cmpint (500, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (0, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + gtd_list_model_filter_set_filter_func (filter, NULL, NULL, NULL); + g_assert_cmpint (500, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + gtd_list_model_filter_set_filter_func (filter, filter_func2, NULL, NULL); + g_assert_cmpint (500, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + { + g_autoptr (TestItem) freeme = test_item_new (1001); + g_list_store_append (model, freeme); + } + + for (i = 0; i < 500; i++) + g_list_store_remove (model, 0); + + g_assert_cmpint (1, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (1, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + gtd_list_model_filter_set_filter_func (filter, NULL, NULL, NULL); + g_assert_cmpint (1, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (1, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + item = g_list_model_get_item (G_LIST_MODEL (filter), 0); + g_assert (item); + g_assert (TEST_IS_ITEM (item)); + g_assert_cmpint (item->n, ==, 1001); + g_clear_object (&item); + + g_clear_object (&model); + g_clear_object (&filter); +} + +static guint last_n_added = 0; +static guint last_n_removed = 0; +static guint last_changed_position = 0; + +static void +model_items_changed_cb (GtdListModelFilter *filter, + guint position, + guint n_removed, + guint n_added, + GListModel *model) +{ + last_n_added = n_added; + last_n_removed = n_removed; + last_changed_position = position; +} + + +static void +filter_items_changed_cb (GtdListModelFilter *filter, + guint position, + guint n_removed, + guint n_added, + GListModel *model) +{ + g_assert_cmpint (n_added, ==, last_n_added); + g_assert_cmpint (n_removed, ==, last_n_removed); + g_assert_cmpint (position, ==, last_changed_position); + +} + +static void +test_items_changed (void) +{ + GtdListModelFilter *filter; + GListStore *model; + guint i; + + model = g_list_store_new (TEST_TYPE_ITEM); + g_assert (model); + + g_signal_connect (model, "items-changed", G_CALLBACK (model_items_changed_cb), NULL); + + filter = gtd_list_model_filter_new (G_LIST_MODEL (model)); + g_assert (filter); + + g_signal_connect_after (filter, "items-changed", G_CALLBACK (filter_items_changed_cb), model); + + for (i = 0; i < 100; i++) + { + g_autoptr (TestItem) val = test_item_new (i); + g_list_store_append (model, val); + } + + g_assert_cmpint (100, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (100, ==, g_list_model_get_n_items (G_LIST_MODEL (filter))); + + for (i = 0; i < 100; i++) + g_list_store_remove (model, 0); + + g_clear_object (&model); + g_clear_object (&filter); +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/models/model-filter/basic", test_basic); + g_test_add_func ("/models/model-filter/items-changed", test_items_changed); + return g_test_run (); +} diff --git a/tests/test-model-sort.c b/tests/test-model-sort.c new file mode 100644 index 0000000..b54b29f --- /dev/null +++ b/tests/test-model-sort.c @@ -0,0 +1,143 @@ +/* test-model-sort.c + * + * Copyright 2018 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "models/gtd-list-model-sort.h" + +#include <math.h> +#include <string.h> + +#define TEST_TYPE_ITEM (test_item_get_type()) + +struct _TestItem +{ + GObject p; + guint n; +}; + +G_DECLARE_FINAL_TYPE (TestItem, test_item, TEST, ITEM, GObject) +G_DEFINE_TYPE (TestItem, test_item, G_TYPE_OBJECT) + +static void +test_item_class_init (TestItemClass *klass) +{ +} + +static void +test_item_init (TestItem *self) +{ +} + +static TestItem * +test_item_new (guint n) +{ + TestItem *item; + + item = g_object_new (TEST_TYPE_ITEM, NULL); + item->n = n; + + return item; +} + +static gint +sort_func1 (GObject *a, + GObject *b, + gpointer user_data) +{ + return TEST_ITEM (a)->n - TEST_ITEM (b)->n; +} + +static gint +sort_func2 (GObject *a, + GObject *b, + gpointer user_data) +{ + return (TEST_ITEM (a)->n & 1) - (TEST_ITEM (b)->n & 1); +} + +static void +test_basic (void) +{ + GtdListModelSort *sort; + GListStore *model; + guint i; + + model = g_list_store_new (TEST_TYPE_ITEM); + g_assert (model); + + sort = gtd_list_model_sort_new (G_LIST_MODEL (model)); + g_assert (sort); + + /* Test requesting past boundary */ + g_assert_null (g_list_model_get_item (G_LIST_MODEL (sort), 0)); + g_assert_null (g_list_model_get_item (G_LIST_MODEL (sort), 1)); + + for (i = 0; i < 1000; i++) + { + g_autoptr (TestItem) val = test_item_new (1000 - i); + g_list_store_append (model, val); + } + + /* Test requesting past boundary */ + g_assert_null (g_list_model_get_item (G_LIST_MODEL (sort), 1000)); + + /* Ascendent sorting */ + gtd_list_model_sort_set_sort_func (sort, sort_func1, NULL, NULL); + + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (sort))); + + for (i = 1; i < 1000; i++) + { + g_autoptr (TestItem) current = g_list_model_get_item (G_LIST_MODEL (sort), i); + g_autoptr (TestItem) previous = g_list_model_get_item (G_LIST_MODEL (sort), i - 1); + + g_assert_cmpint (previous->n, <, current->n); + } + + /* Odd/Even sorting */ + gtd_list_model_sort_set_sort_func (sort, sort_func2, NULL, NULL); + + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (model))); + g_assert_cmpint (1000, ==, g_list_model_get_n_items (G_LIST_MODEL (sort))); + + for (i = 0; i < 1000; i++) + { + g_autoptr (TestItem) current = g_list_model_get_item (G_LIST_MODEL (sort), i); + + if (i < 500) + g_assert_cmpint (current->n % 2, ==, 0); + else + g_assert_cmpint (current->n % 2, ==, 1); + } + + g_clear_object (&model); + g_clear_object (&sort); +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/models/model-sort/basic", test_basic); + + return g_test_run (); +} diff --git a/tests/test-task-list.c b/tests/test-task-list.c new file mode 100644 index 0000000..cee6adb --- /dev/null +++ b/tests/test-task-list.c @@ -0,0 +1,99 @@ +/* test-task-model.c + * + * Copyright 2018-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "endeavour.h" + +#include "core/gtd-log.h" +#include "gtd-task-list.h" +#include "gtd-manager-protected.h" +#include "dummy-provider.h" + +static void +test_move (void) +{ + g_autoptr (DummyProvider) dummy_provider = NULL; + g_autoptr (GtdTask) first_task = NULL; + g_autoptr (GtdTask) last_task = NULL; + g_autoptr (GList) lists = NULL; + GtdTaskList *list = NULL; + GListModel *model; + guint n_tasks; + + dummy_provider = dummy_provider_new (); + n_tasks = dummy_provider_generate_task_list (dummy_provider); + g_assert_cmpuint (n_tasks, ==, 10); + + gtd_manager_add_provider (gtd_manager_get_default (), GTD_PROVIDER (dummy_provider)); + + lists = gtd_provider_get_task_lists (GTD_PROVIDER (dummy_provider)); + g_assert_nonnull (lists); + g_assert_cmpint (g_list_length (lists), ==, 1); + + list = lists->data; + model = G_LIST_MODEL (list); + g_assert_nonnull (list); + g_assert_cmpstr (gtd_task_list_get_name (list), ==, "List"); + + first_task = g_list_model_get_item (model, 0); + g_assert_nonnull (first_task); + g_assert_cmpint (gtd_task_get_position (first_task), ==, 0); + g_assert_true (g_list_model_get_item (model, 0) == first_task); + + last_task = g_list_model_get_item (model, 9); + g_assert_nonnull (last_task); + g_assert_cmpint (gtd_task_get_position (last_task), ==, 9); + g_assert_true (g_list_model_get_item (model, 9) == last_task); + + /* Move the task to 0 */ + gtd_task_list_move_task_to_position (list, last_task, 0); + + g_assert_cmpint (gtd_task_get_position (last_task), ==, 0); + g_assert_cmpint (gtd_task_get_position (first_task), ==, 1); + g_assert_true (g_list_model_get_item (model, 0) == last_task); + g_assert_true (g_list_model_get_item (model, 1) == first_task); + + /* Move the task to 1 */ + gtd_task_list_move_task_to_position (list, last_task, 1); + + g_assert_cmpint (gtd_task_get_position (last_task), ==, 1); + g_assert_cmpint (gtd_task_get_position (first_task), ==, 0); + g_assert_true (g_list_model_get_item (model, 0) == first_task); + g_assert_true (g_list_model_get_item (model, 1) == last_task); + + /* Move the task to 9 */ + gtd_task_list_move_task_to_position (list, last_task, 9); + + g_assert_cmpint (gtd_task_get_position (last_task), ==, 9); + g_assert_true (g_list_model_get_item (model, 9) == last_task); +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + if (g_getenv ("G_MESSAGES_DEBUG")) + gtd_log_init (); + + g_test_add_func ("/task-list/move", test_move); + + return g_test_run (); +} diff --git a/tests/test-task-model.c b/tests/test-task-model.c new file mode 100644 index 0000000..04da5a6 --- /dev/null +++ b/tests/test-task-model.c @@ -0,0 +1,67 @@ +/* test-task-model.c + * + * Copyright 2018-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "endeavour.h" + +#include "core/gtd-log.h" +#include "models/gtd-task-model.h" +#include "models/gtd-task-model-private.h" +#include "gtd-manager-protected.h" +#include "dummy-provider.h" + +static void +test_basic (void) +{ + g_autoptr (DummyProvider) dummy_provider = NULL; + GtdTaskModel *model = NULL; + guint n_tasks; + + /* Create a DumbProvider and pre-populate it */ + dummy_provider = dummy_provider_new (); + n_tasks = dummy_provider_generate_task_lists (dummy_provider); + gtd_manager_add_provider (gtd_manager_get_default (), GTD_PROVIDER (dummy_provider)); + + model = _gtd_task_model_new (gtd_manager_get_default ()); + g_assert_cmpint (g_list_model_get_n_items (G_LIST_MODEL (model)), ==, n_tasks); + + /* Generate more */ + n_tasks = dummy_provider_generate_task_lists (dummy_provider); + g_assert_cmpint (g_list_model_get_n_items (G_LIST_MODEL (model)), ==, n_tasks); + + while (n_tasks > 0) + { + n_tasks = dummy_provider_randomly_remove_task (dummy_provider); + g_assert_cmpint (g_list_model_get_n_items (G_LIST_MODEL (model)), ==, n_tasks); + } +} + +gint +main (gint argc, + gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + if (g_getenv ("G_MESSAGES_DEBUG")) + gtd_log_init (); + + g_test_add_func ("/models/task-model/basic", test_basic); + + return g_test_run (); +} |
