From fc8ab634a8fba3f88e38dad06e0152e0d431838e Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 25 Oct 2010 14:32:22 +0200 Subject: [PATCH] app/tests: Add '/gimp-tools/crop_tool_can_crop' test Begin adding a new set of tests meant to test tools. The first test is a regression test for "Bug 315255 - SIGSEGV, while doing a crop". --- app/tests/.gitignore | 1 + app/tests/Makefile.am | 1 + app/tests/test-tools.c | 432 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 434 insertions(+) create mode 100644 app/tests/test-tools.c diff --git a/app/tests/.gitignore b/app/tests/.gitignore index 9c58683ba2..2e2561ded2 100644 --- a/app/tests/.gitignore +++ b/app/tests/.gitignore @@ -7,6 +7,7 @@ libgimpapptestutils.a test-core* test-layer-grouping* test-session-management* +test-tools* test-ui* test-window-management* test-xcf* diff --git a/app/tests/Makefile.am b/app/tests/Makefile.am index 6acfe07036..c981c4ffb9 100644 --- a/app/tests/Makefile.am +++ b/app/tests/Makefile.am @@ -13,6 +13,7 @@ TESTS_ENVIRONMENT = \ TESTS = \ test-core \ test-session-management \ + test-tools \ test-ui \ test-xcf diff --git a/app/tests/test-tools.c b/app/tests/test-tools.c new file mode 100644 index 0000000000..0c43bdd8e7 --- /dev/null +++ b/app/tests/test-tools.c @@ -0,0 +1,432 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 2009 Martin Nordholts + * + * 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 . + */ + +#include +#include + +#include +#include +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "tools/tools-types.h" + +#include "tools/tool_manager.h" + +#include "display/gimpdisplay.h" +#include "display/gimpdisplayshell.h" +#include "display/gimpdisplayshell-scale.h" +#include "display/gimpdisplayshell-callbacks.h" +#include "display/gimpdisplayshell-transform.h" +#include "display/gimpimagewindow.h" + +#include "widgets/gimpdialogfactory.h" +#include "widgets/gimpdock.h" +#include "widgets/gimpdockable.h" +#include "widgets/gimpdockbook.h" +#include "widgets/gimpdocked.h" +#include "widgets/gimpdockwindow.h" +#include "widgets/gimphelp-ids.h" +#include "widgets/gimpsessioninfo.h" +#include "widgets/gimptoolbox.h" +#include "widgets/gimptooloptionseditor.h" +#include "widgets/gimpuimanager.h" +#include "widgets/gimpwidgets-utils.h" + +#include "core/gimp.h" +#include "core/gimpchannel.h" +#include "core/gimpcontext.h" +#include "core/gimpimage.h" +#include "core/gimplayer.h" +#include "core/gimptoolinfo.h" +#include "core/gimptooloptions.h" + +#include "tests.h" + +#include "gimp-app-test-utils.h" + + +#define GIMP_TEST_IMAGE_WIDTH 150 +#define GIMP_TEST_IMAGE_HEIGHT 267 + +/* Put this in the code below when you want the test to pause so you + * can do measurements of widgets on the screen for example + */ +#define GIMP_PAUSE (g_usleep (2 * 1000 * 1000)) + +#define ADD_TEST(function) \ + g_test_add ("/gimp-tools/" #function, \ + GimpTestFixture, \ + gimp, \ + gimp_tools_setup_image, \ + function, \ + gimp_tools_teardown_image); + + +typedef struct +{ + int avoid_sizeof_zero; +} GimpTestFixture; + + +static void gimp_tools_setup_image (GimpTestFixture *fixture, + gconstpointer data); +static void gimp_tools_teardown_image (GimpTestFixture *fixture, + gconstpointer data); +static void gimp_tools_synthesize_image_click_drag_release (GimpDisplayShell *shell, + gdouble start_image_x, + gdouble start_image_y, + gdouble end_image_x, + gdouble end_image_y, + gint button, + GdkModifierType modifiers); +static GimpDisplay * gimp_test_get_only_display (Gimp *gimp); +static GimpImage * gimp_test_get_only_image (Gimp *gimp); +static GimpDisplayShell * gimp_test_get_only_display_shell (Gimp *gimp); + + +static void +gimp_tools_setup_image (GimpTestFixture *fixture, + gconstpointer data) +{ + Gimp *gimp = GIMP (data); + + gimp_test_utils_create_image (gimp, + GIMP_TEST_IMAGE_WIDTH, + GIMP_TEST_IMAGE_HEIGHT); + gimp_test_run_mainloop_until_idle (); +} + +static void +gimp_tools_teardown_image (GimpTestFixture *fixture, + gconstpointer data) +{ + Gimp *gimp = GIMP (data); + + g_object_unref (gimp_test_get_only_image (gimp)); + gimp_display_close (gimp_test_get_only_display (gimp)); + gimp_test_run_mainloop_until_idle (); +} + +/** + * gimp_test_get_only_display: + * @gimp: + * + * Asserts that there only is one image and display and then + * returns the display. + * + * Returns: The #GimpDisplay. + **/ +static GimpDisplay * +gimp_test_get_only_display (Gimp *gimp) +{ + g_assert (g_list_length (gimp_get_image_iter (gimp)) == 1); + g_assert (g_list_length (gimp_get_display_iter (gimp)) == 1); + + return GIMP_DISPLAY (gimp_get_display_iter (gimp)->data); +} + +/** + * gimp_test_get_only_display_shell: + * @gimp: + * + * Asserts that there only is one image and display shell and then + * returns the display shell. + * + * Returns: The #GimpDisplayShell. + **/ +static GimpDisplayShell * +gimp_test_get_only_display_shell (Gimp *gimp) +{ + return gimp_display_get_shell (gimp_test_get_only_display (gimp)); +} + +/** + * gimp_test_get_only_image: + * @gimp: + * + * Asserts that there is only one image and returns that. + * + * Returns: The #GimpImage. + **/ +static GimpImage * +gimp_test_get_only_image (Gimp *gimp) +{ + g_assert (g_list_length (gimp_get_image_iter (gimp)) == 1); + g_assert (g_list_length (gimp_get_display_iter (gimp)) == 1); + + return GIMP_IMAGE (gimp_get_image_iter (gimp)->data); +} + +static void +gimp_test_synthesize_tool_button_event (GimpDisplayShell *shell, + gint x, + gint y, + gint button, + gint modifiers, + GdkEventType button_event_type) +{ + GdkEvent *event = gdk_event_new (button_event_type); + GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (shell->canvas)); + GdkDisplay *display = gdk_drawable_get_display (GDK_DRAWABLE (window)); + + g_assert (button_event_type == GDK_BUTTON_PRESS || + button_event_type == GDK_BUTTON_RELEASE); + + event->button.window = g_object_ref (window); + event->button.send_event = TRUE; + event->button.time = gtk_get_current_event_time (); + event->button.x = x; + event->button.y = y; + event->button.axes = NULL; + event->button.state = 0; + event->button.button = button; + event->button.device = gdk_display_get_core_pointer (display); + event->button.x_root = -1; + event->button.y_root = -1; + + gimp_display_shell_canvas_tool_events (shell->canvas, + event, + shell); + gdk_event_free (event); +} + +static void +gimp_test_synthesize_tool_motion_event (GimpDisplayShell *shell, + gint x, + gint y, + gint modifiers) +{ + GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY); + GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (shell->canvas)); + GdkDisplay *display = gdk_drawable_get_display (GDK_DRAWABLE (window)); + + event->motion.window = g_object_ref (window); + event->motion.send_event = TRUE; + event->motion.time = gtk_get_current_event_time (); + event->motion.x = x; + event->motion.y = y; + event->motion.axes = NULL; + event->motion.state = GDK_BUTTON1_MASK | modifiers; + event->motion.is_hint = FALSE; + event->motion.device = gdk_display_get_core_pointer (display); + event->motion.x_root = -1; + event->motion.y_root = -1; + + gimp_display_shell_canvas_tool_events (shell->canvas, + event, + shell); + gdk_event_free (event); +} + +static void +gimp_test_synthesize_tool_crossing_event (GimpDisplayShell *shell, + gint x, + gint y, + gint modifiers, + GdkEventType crossing_event_type) +{ + GdkEvent *event = gdk_event_new (crossing_event_type); + GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (shell->canvas)); + + g_assert (crossing_event_type == GDK_ENTER_NOTIFY || + crossing_event_type == GDK_LEAVE_NOTIFY); + + event->crossing.window = g_object_ref (window); + event->crossing.send_event = TRUE; + event->crossing.subwindow = NULL; + event->crossing.time = gtk_get_current_event_time (); + event->crossing.x = x; + event->crossing.y = y; + event->crossing.x_root = -1; + event->crossing.y_root = -1; + event->crossing.mode = GDK_CROSSING_NORMAL; + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + event->crossing.focus = TRUE; + event->crossing.state = modifiers; + + gimp_display_shell_canvas_tool_events (shell->canvas, + event, + shell); + gdk_event_free (event); +} + +static void +gimp_tools_synthesize_image_click_drag_release (GimpDisplayShell *shell, + gdouble start_image_x, + gdouble start_image_y, + gdouble end_image_x, + gdouble end_image_y, + gint button /*1..3*/, + GdkModifierType modifiers) +{ + gdouble start_canvas_x = -1.0; + gdouble start_canvas_y = -1.0; + gdouble end_canvas_x = -1.0; + gdouble end_canvas_y = -1.0; + gdouble middle_canvas_x = -1.0; + gdouble middle_canvas_y = -1.0; + + /* Transform coordinates */ + gimp_display_shell_transform_xy_f (shell, + start_image_x, + start_image_y, + &start_canvas_x, + &start_canvas_y); + gimp_display_shell_transform_xy_f (shell, + end_image_x, + end_image_y, + &end_canvas_x, + &end_canvas_y); + middle_canvas_x = (start_canvas_x + end_canvas_x) / 2; + middle_canvas_y = (start_canvas_y + end_canvas_y) / 2; + + /* Enter notify */ + gimp_test_synthesize_tool_crossing_event (shell, + (int)start_canvas_x, + (int)start_canvas_y, + modifiers, + GDK_ENTER_NOTIFY); + + /* Button press */ + gimp_test_synthesize_tool_button_event (shell, + (int)start_canvas_x, + (int)start_canvas_y, + button, + modifiers, + GDK_BUTTON_PRESS); + + /* Move events */ + gimp_test_synthesize_tool_motion_event (shell, + (int)start_canvas_x, + (int)start_canvas_y, + modifiers); + gimp_test_synthesize_tool_motion_event (shell, + (int)middle_canvas_x, + (int)middle_canvas_y, + modifiers); + gimp_test_synthesize_tool_motion_event (shell, + (int)end_canvas_x, + (int)end_canvas_y, + modifiers); + + /* Button release */ + gimp_test_synthesize_tool_button_event (shell, + (int)end_canvas_x, + (int)end_canvas_y, + button, + modifiers, + GDK_BUTTON_RELEASE); + + /* Leave notify */ + gimp_test_synthesize_tool_crossing_event (shell, + (int)start_canvas_x, + (int)start_canvas_y, + modifiers, + GDK_LEAVE_NOTIFY); + + /* Process them */ + gimp_test_run_mainloop_until_idle (); +} + +/** + * crop_tool_can_crop: + * @fixture: + * @data: + * + * Make sure it's possible to crop at all. Regression test for bug + * 315255. + **/ +static void +crop_tool_can_crop (GimpTestFixture *fixture, + gconstpointer data) +{ + Gimp *gimp = GIMP (data); + GimpImage *image = gimp_test_get_only_image (gimp); + GimpDisplayShell *shell = gimp_test_get_only_display_shell (gimp); + + gint cropped_x = 10; + gint cropped_y = 10; + gint cropped_w = 20; + gint cropped_h = 30; + + /* Fit display and pause and let it stabalize (two idlings seems to + * always be enough) + */ + gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp), + "view", + "view-shrink-wrap"); + gimp_test_run_mainloop_until_idle (); + gimp_test_run_mainloop_until_idle (); + + /* Activate tool and setup active display for the new tool */ + gimp_context_set_tool (gimp_get_user_context (gimp), + gimp_get_tool_info (gimp, "gimp-crop-tool")); + tool_manager_focus_display_active (gimp, shell->display); + + /* Do the crop rect */ + gimp_tools_synthesize_image_click_drag_release (shell, + cropped_x, + cropped_y, + cropped_x + cropped_w, + cropped_y + cropped_h, + 1 /*button*/, + 0 /*modifiers*/); + + /* Crop */ + gimp_test_utils_synthesize_key_event (GTK_WIDGET (shell), GDK_Return); + gimp_test_run_mainloop_until_idle (); + + /* Make sure the new image has the expected size */ + g_assert_cmpint (cropped_w, ==, gimp_image_get_width (image)); + g_assert_cmpint (cropped_h, ==, gimp_image_get_height (image)); +} + +int main(int argc, char **argv) +{ + Gimp *gimp = NULL; + gint result = -1; + + gimp_test_bail_if_no_display (); + gtk_test_init (&argc, &argv, NULL); + + gimp_test_utils_set_gimp2_directory ("GIMP_TESTING_ABS_TOP_SRCDIR", + "app/tests/gimpdir"); + gimp_test_utils_setup_menus_dir (); + + /* Start up GIMP */ + gimp = gimp_init_for_gui_testing (TRUE /*show_gui*/); + gimp_test_run_mainloop_until_idle (); + + /* Add tests */ + ADD_TEST (crop_tool_can_crop); + + /* Run the tests and return status */ + result = g_test_run (); + + /* Don't write files to the source dir */ + gimp_test_utils_set_gimp2_directory ("GIMP_TESTING_ABS_TOP_BUILDDIR", + "app/tests/gimpdir-output"); + + /* Exit properly so we don't break script-fu plug-in wire */ + gimp_exit (gimp, TRUE); + + return result; +}