[evolution/wip/webkit2] Initial simple automated EHTMLEditor tests
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/webkit2] Initial simple automated EHTMLEditor tests
- Date: Tue, 21 Jun 2016 17:54:47 +0000 (UTC)
commit 8efb29c4f35211a2cccc7ef21d29a285f872a4f7
Author: Milan Crha <mcrha redhat com>
Date: Tue Jun 21 19:53:52 2016 +0200
Initial simple automated EHTMLEditor tests
e-util/Makefile.am | 9 +
e-util/e-html-editor-private.h | 4 +
e-util/e-html-editor.c | 23 +
e-util/test-html-editor-units-utils.c | 810 ++++++++++++++++++++
e-util/test-html-editor-units-utils.h | 53 ++
e-util/test-html-editor-units.c | 230 ++++++
modules/webkit-editor/e-webkit-editor.c | 31 +-
modules/webkit-editor/web-extension/Makefile.am | 2 +
.../e-html-editor-test-dom-functions.c | 69 ++
.../e-html-editor-test-dom-functions.h | 26 +
.../web-extension/e-html-editor-web-extension.c | 27 +-
11 files changed, 1282 insertions(+), 2 deletions(-)
---
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 43cd869..b6e9faa 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -61,6 +61,7 @@ noinst_PROGRAMS = \
test-category-completion \
test-contact-store \
test-dateedit \
+ test-html-editor-units \
test-mail-signatures \
test-name-selector \
test-preferences-window \
@@ -690,6 +691,14 @@ test_dateedit_LDADD = $(TEST_LDADD)
#test_html_editor_SOURCES = test-html-editor.c
#test_html_editor_LDADD = $(TEST_LDADD)
+test_html_editor_units_CPPFLAGS = $(TEST_CPPFLAGS) -DTEST_TOP_SRCDIR=\""$(top_srcdir)"\"
+test_html_editor_units_SOURCES = \
+ test-html-editor-units-utils.h \
+ test-html-editor-units-utils.c \
+ test-html-editor-units.c \
+ $(NULL)
+test_html_editor_units_LDADD = $(TEST_LDADD)
+
test_mail_signatures_CPPFLAGS = $(TEST_CPPFLAGS)
test_mail_signatures_SOURCES = test-mail-signatures.c
test_mail_signatures_LDADD = $(TEST_LDADD)
diff --git a/e-util/e-html-editor-private.h b/e-util/e-html-editor-private.h
index d201214..37523a5 100644
--- a/e-util/e-html-editor-private.h
+++ b/e-util/e-html-editor-private.h
@@ -93,10 +93,14 @@ struct _EHTMLEditorPrivate {
guint spell_suggestions_merge_id;
gint editor_layout_row;
+
+ gboolean is_testing;
};
void editor_actions_init (EHTMLEditor *editor);
void editor_actions_bind (EHTMLEditor *editor);
+const gchar * e_html_editor_get_content_editor_name
+ (EHTMLEditor *editor);
G_END_DECLS
diff --git a/e-util/e-html-editor.c b/e-util/e-html-editor.c
index 30d256e..c2f495a 100644
--- a/e-util/e-html-editor.c
+++ b/e-util/e-html-editor.c
@@ -956,6 +956,29 @@ e_html_editor_get_content_editor (EHTMLEditor *editor)
return editor->priv->use_content_editor;
}
+/* Private function */
+const gchar *
+e_html_editor_get_content_editor_name (EHTMLEditor *editor)
+{
+ EContentEditor *cnt_editor;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (!cnt_editor)
+ return NULL;
+
+ g_hash_table_iter_init (&iter, editor->priv->content_editors);
+ if (g_hash_table_iter_next (&iter, &key, &value)) {
+ if (value == cnt_editor)
+ return key;
+ }
+
+ return NULL;
+}
+
void
e_html_editor_register_content_editor (EHTMLEditor *editor,
const gchar *name,
diff --git a/e-util/test-html-editor-units-utils.c b/e-util/test-html-editor-units-utils.c
new file mode 100644
index 0000000..a1d8b34
--- /dev/null
+++ b/e-util/test-html-editor-units-utils.c
@@ -0,0 +1,810 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "e-util/e-util.h"
+
+#include "test-html-editor-units-utils.h"
+
+typedef struct _UndoContent {
+ gchar *html;
+ gchar *plain;
+} UndoContent;
+
+static UndoContent *
+undo_content_new (TestFixture *fixture)
+{
+ EContentEditor *cnt_editor;
+ UndoContent *uc;
+
+ g_return_val_if_fail (fixture != NULL, NULL);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+
+ uc = g_new0 (UndoContent, 1);
+ uc->html = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL);
+ uc->plain = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL);
+
+ g_warn_if_fail (uc->html != NULL);
+ g_warn_if_fail (uc->plain != NULL);
+
+ return uc;
+}
+
+static void
+undo_content_free (gpointer ptr)
+{
+ UndoContent *uc = ptr;
+
+ if (uc) {
+ g_free (uc->html);
+ g_free (uc->plain);
+ g_free (uc);
+ }
+}
+
+static gboolean
+undo_content_test (TestFixture *fixture,
+ const UndoContent *uc)
+{
+ EContentEditor *cnt_editor;
+ gchar *text;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (uc != NULL, FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, uc->html)) {
+ g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not match",
G_STRFUNC, text, uc->html);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, uc->plain)) {
+ g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not match",
G_STRFUNC, text, uc->plain);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+
+ return TRUE;
+}
+
+void
+test_utils_fixture_set_up (TestFixture *fixture,
+ gconstpointer user_data)
+{
+ EContentEditor *cnt_editor;
+ GSettings *settings;
+ gpointer async_data;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+ fixture->prompt_on_composer_mode_switch = g_settings_get_boolean (settings,
"prompt-on-composer-mode-switch");
+ fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ fixture->editor = E_HTML_EDITOR (e_html_editor_new ());
+ fixture->undo_stack = NULL;
+
+ g_object_set (G_OBJECT (fixture->editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ NULL);
+ gtk_widget_show (GTK_WIDGET (fixture->editor));
+ gtk_container_add (GTK_CONTAINER (fixture->window), GTK_WIDGET (fixture->editor));
+
+ /* Turn this off; it may be left off on test failures */
+ g_settings_set_boolean (settings, "prompt-on-composer-mode-switch", FALSE);
+
+ g_clear_object (&settings);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ g_object_set (G_OBJECT (cnt_editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ "height-request", 150,
+ NULL);
+
+ async_data = test_utils_async_call_prepare ();
+
+ g_signal_connect_swapped (cnt_editor, "notify::web-extension",
+ G_CALLBACK (test_utils_async_call_finish), async_data);
+
+ gtk_window_set_focus (GTK_WINDOW (fixture->window), GTK_WIDGET (cnt_editor));
+ gtk_widget_show (fixture->window);
+
+ test_utils_async_call_wait (async_data, 5);
+}
+
+void
+test_utils_fixture_tear_down (TestFixture *fixture,
+ gconstpointer user_data)
+{
+ GSettings *settings;
+
+ gtk_widget_destroy (GTK_WIDGET (fixture->window));
+ fixture->editor = NULL;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ g_settings_set_boolean (settings, "prompt-on-composer-mode-switch",
fixture->prompt_on_composer_mode_switch);
+ g_clear_object (&settings);
+
+ g_slist_free_full (fixture->undo_stack, undo_content_free);
+ fixture->undo_stack = NULL;
+}
+
+static void
+test_utils_flush_main_context (void)
+{
+ GMainContext *main_context;
+
+ main_context = g_main_context_default ();
+
+ while (g_main_context_pending (main_context)) {
+ g_main_context_iteration (main_context, FALSE);
+ }
+}
+
+gpointer
+test_utils_async_call_prepare (void)
+{
+ return g_main_loop_new (NULL, FALSE);
+}
+
+typedef struct _AsynCallData {
+ GMainLoop *loop;
+ gboolean timeout_reached;
+} AsyncCallData;
+
+static gboolean
+test_utils_async_call_timeout_reached_cb (gpointer user_data)
+{
+ AsyncCallData *async_call_data = user_data;
+
+ g_return_val_if_fail (async_call_data != NULL, FALSE);
+ g_return_val_if_fail (async_call_data->loop != NULL, FALSE);
+ g_return_val_if_fail (!async_call_data->timeout_reached, FALSE);
+
+ if (!g_source_is_destroyed (g_main_current_source ())) {
+ async_call_data->timeout_reached = TRUE;
+ g_main_loop_quit (async_call_data->loop);
+ }
+
+ return FALSE;
+}
+
+gboolean
+test_utils_async_call_wait (gpointer async_data,
+ guint timeout_seconds)
+{
+ GMainLoop *loop = async_data;
+ AsyncCallData async_call_data;
+ GSource *source = NULL;
+
+ g_return_val_if_fail (loop != NULL, FALSE);
+
+ async_call_data.loop = loop;
+ async_call_data.timeout_reached = FALSE;
+
+ /* 0 is to wait forever */
+ if (timeout_seconds > 0) {
+ source = g_timeout_source_new_seconds (timeout_seconds);
+ g_source_set_callback (source, test_utils_async_call_timeout_reached_cb, &async_call_data,
NULL);
+ g_source_attach (source, NULL);
+ }
+
+ g_main_loop_run (loop);
+
+ if (source) {
+ g_source_destroy (source);
+ g_source_unref (source);
+ }
+
+ test_utils_flush_main_context ();
+
+ g_main_loop_unref (loop);
+
+ return !async_call_data.timeout_reached;
+}
+
+gboolean
+test_utils_async_call_finish (gpointer async_data)
+{
+ GMainLoop *loop = async_data;
+
+ g_return_val_if_fail (loop != NULL, FALSE);
+
+ g_main_loop_quit (loop);
+
+ return FALSE;
+}
+
+gboolean
+test_utils_wait_milliseconds (guint milliseconds)
+{
+ gpointer async_data;
+
+ async_data = test_utils_async_call_prepare ();
+ g_timeout_add (milliseconds, test_utils_async_call_finish, async_data);
+
+ return test_utils_async_call_wait (async_data, milliseconds / 1000 + 1);
+}
+
+gboolean
+test_utils_type_text (TestFixture *fixture,
+ const gchar *text)
+{
+ GtkWidget *widget;
+ GdkKeymap *keymap;
+ GdkEvent event;
+ gboolean none_failed = TRUE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+
+ widget = GTK_WIDGET (e_html_editor_get_content_editor (fixture->editor));
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ g_return_val_if_fail (text != NULL, FALSE);
+ g_return_val_if_fail (g_utf8_validate (text, -1, NULL), FALSE);
+
+ event.key.window = gtk_widget_get_window (widget);
+ event.key.send_event = TRUE;
+ event.key.length = 0;
+ event.key.string = NULL;
+ event.key.is_modifier = FALSE;
+
+ keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
+
+ while (*text && none_failed) {
+ GdkKeymapKey *keys = NULL;
+ gint n_keys;
+ gunichar unichar;
+
+ unichar = g_utf8_get_char (text);
+ text = g_utf8_next_char (text);
+
+ event.key.keyval = gdk_unicode_to_keyval (unichar);
+
+ if (gdk_keymap_get_entries_for_keyval (keymap, event.key.keyval, &keys, &n_keys) && n_keys >
0) {
+ GdkEvent *nevent;
+
+ nevent = gdk_event_new (GDK_KEY_PRESS);
+ nevent->key.keyval = event.key.keyval;
+ nevent->key.state = event.key.state;
+ nevent->key.window = g_object_ref (event.key.window);
+ nevent->key.send_event = event.key.send_event;
+ nevent->key.length = event.key.length;
+ nevent->key.string = event.key.string;
+ nevent->key.is_modifier = event.key.is_modifier;
+ gdk_event_set_device (nevent, gdk_seat_get_keyboard (gdk_display_get_default_seat
(gtk_widget_get_display (widget))));
+ nevent->key.hardware_keycode = keys[0].keycode;
+ nevent->key.group = keys[0].group;
+
+ nevent->key.type = GDK_KEY_PRESS;
+ nevent->key.time = GDK_CURRENT_TIME;
+ gtk_main_do_event (nevent);
+
+ test_utils_wait_milliseconds (5);
+
+ nevent->key.type = GDK_KEY_RELEASE;
+ nevent->key.time = GDK_CURRENT_TIME;
+ gtk_main_do_event (nevent);
+
+ test_utils_wait_milliseconds (5);
+
+ gdk_event_free (nevent);
+ } else {
+ none_failed = FALSE;
+ g_warning ("%s: Nothing found for unichar '%x'", G_STRFUNC, unichar);
+ }
+
+ g_free (keys);
+ }
+
+ test_utils_wait_milliseconds (5);
+
+ return none_failed;
+}
+
+gboolean
+test_utils_html_equal (TestFixture *fixture,
+ const gchar *html1,
+ const gchar *html2)
+{
+ EContentEditor *cnt_editor;
+ GDBusProxy *web_extension = NULL;
+ GVariant *result;
+ GError *error = NULL;
+ gboolean html_equal = FALSE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (html1 != NULL, FALSE);
+ g_return_val_if_fail (html2 != NULL, FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ g_return_val_if_fail (cnt_editor != NULL, FALSE);
+
+ g_object_get (cnt_editor, "web-extension", &web_extension, NULL);
+
+ g_return_val_if_fail (G_IS_DBUS_PROXY (web_extension), FALSE);
+
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "TestHtmlEqual",
+ g_variant_new ("(tss)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (cnt_editor)), html1,
html2),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+
+ g_return_val_if_fail (result != NULL, FALSE);
+
+ g_variant_get (result, "(b)", &html_equal);
+ g_variant_unref (result);
+
+ return html_equal;
+}
+
+static gboolean
+test_utils_process_sequence (TestFixture *fixture,
+ const gchar *sequence)
+{
+ GtkWidget *widget;
+ GdkKeymap *keymap;
+ GdkEvent event;
+ const gchar *seq;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (sequence != NULL, FALSE);
+
+ widget = GTK_WIDGET (e_html_editor_get_content_editor (fixture->editor));
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
+
+ event.key.window = gtk_widget_get_window (widget);
+ event.key.send_event = FALSE;
+ event.key.state = 0;
+ event.key.length = 0;
+ event.key.string = NULL;
+
+ for (seq = sequence; *seq && success; seq++) {
+ gboolean call_press = TRUE, call_release = TRUE;
+ guint32 change_state = event.key.state;
+
+ event.key.is_modifier = FALSE;
+
+ switch (*seq) {
+ case 'S': /* Shift key press */
+ event.key.keyval = GDK_KEY_Shift_L;
+ event.key.is_modifier = TRUE;
+
+ if ((event.key.state & GDK_SHIFT_MASK) != 0) {
+ success = FALSE;
+ g_warning ("%s: Shift is already pressed", G_STRFUNC);
+ } else {
+ change_state |= GDK_SHIFT_MASK;
+ }
+ call_release = FALSE;
+ break;
+ case 's': /* Shift key release */
+ event.key.keyval = GDK_KEY_Shift_L;
+ event.key.is_modifier = TRUE;
+
+ if ((event.key.state & GDK_SHIFT_MASK) == 0) {
+ success = FALSE;
+ g_warning ("%s: Shift is already released", G_STRFUNC);
+ } else {
+ change_state &= ~GDK_SHIFT_MASK;
+ }
+ call_press = FALSE;
+ break;
+ case 'C': /* Ctrl key press */
+ event.key.keyval = GDK_KEY_Control_L;
+ event.key.is_modifier = TRUE;
+
+ if ((event.key.state & GDK_CONTROL_MASK) != 0) {
+ success = FALSE;
+ g_warning ("%s: Control is already pressed", G_STRFUNC);
+ } else {
+ change_state |= GDK_CONTROL_MASK;
+ }
+ call_release = FALSE;
+ break;
+ case 'c': /* Ctrl key release */
+ event.key.keyval = GDK_KEY_Control_L;
+ event.key.is_modifier = TRUE;
+
+ if ((event.key.state & GDK_CONTROL_MASK) == 0) {
+ success = FALSE;
+ g_warning ("%s: Control is already released", G_STRFUNC);
+ } else {
+ change_state &= ~GDK_CONTROL_MASK;
+ }
+ call_press = FALSE;
+ break;
+ case 'h': /* Home key press + release */
+ event.key.keyval = GDK_KEY_Home;
+ break;
+ case 'e': /* End key press + release */
+ event.key.keyval = GDK_KEY_End;
+ break;
+ case 'P': /* Page-Up key press + release */
+ event.key.keyval = GDK_KEY_Page_Up;
+ break;
+ case 'p': /* Page-Down key press + release */
+ event.key.keyval = GDK_KEY_Page_Down;
+ break;
+ case 'l': /* Arrow-Left key press + release */
+ event.key.keyval = GDK_KEY_Left;
+ break;
+ case 'r': /* Arrow-Right key press + release */
+ event.key.keyval = GDK_KEY_Right;
+ break;
+ case 'u': /* Arrow-Up key press + release */
+ event.key.keyval = GDK_KEY_Up;
+ break;
+ case 'd': /* Arrow-Down key press + release */
+ event.key.keyval = GDK_KEY_Down;
+ break;
+ case 'D': /* Delete key press + release */
+ event.key.keyval = GDK_KEY_Delete;
+ break;
+ case 'b': /* Backspace key press + release */
+ event.key.keyval = GDK_KEY_BackSpace;
+ break;
+ case 't': /* Tab key press + release */
+ event.key.keyval = GDK_KEY_Tab;
+ break;
+ case 'n': /* Return key press + release */
+ event.key.keyval = GDK_KEY_Return;
+ break;
+ default:
+ success = FALSE;
+ g_warning ("%s: Unknown sequence command '%c' in sequence '%s'", G_STRFUNC, *seq,
sequence);
+ break;
+ }
+
+ if (success && (call_press || call_release)) {
+ GdkKeymapKey *keys = NULL;
+ gint n_keys;
+
+ if (gdk_keymap_get_entries_for_keyval (keymap, event.key.keyval, &keys, &n_keys) &&
n_keys > 0) {
+ GdkEvent *nevent;
+
+ nevent = gdk_event_new (GDK_KEY_PRESS);
+ nevent->key.keyval = event.key.keyval;
+ nevent->key.state = event.key.state;
+ nevent->key.window = g_object_ref (event.key.window);
+ nevent->key.send_event = event.key.send_event;
+ nevent->key.length = event.key.length;
+ nevent->key.string = event.key.string;
+ nevent->key.is_modifier = event.key.is_modifier;
+ gdk_event_set_device (nevent, gdk_seat_get_keyboard
(gdk_display_get_default_seat (gtk_widget_get_display (widget))));
+ nevent->key.hardware_keycode = keys[0].keycode;
+ nevent->key.group = keys[0].group;
+
+ if (call_press) {
+ nevent->key.type = GDK_KEY_PRESS;
+ nevent->key.time = GDK_CURRENT_TIME;
+ gtk_main_do_event (nevent);
+
+ test_utils_wait_milliseconds (5);
+ }
+
+ if (call_release) {
+ nevent->key.type = GDK_KEY_RELEASE;
+ nevent->key.time = GDK_CURRENT_TIME;
+ gtk_main_do_event (nevent);
+
+ test_utils_wait_milliseconds (5);
+ }
+
+ gdk_event_free (nevent);
+ } else {
+ success = FALSE;
+ g_warning ("%s: Failed to get keymap entries for sequence command '%c'",
G_STRFUNC, *seq);
+ }
+
+ g_free (keys);
+ }
+
+ event.key.state = change_state;
+ }
+
+ test_utils_wait_milliseconds (5);
+
+ return success;
+}
+
+static gboolean
+test_utils_execute_action (TestFixture *fixture,
+ const gchar *action_name)
+{
+ GtkAction *action;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (action_name != NULL, FALSE);
+
+ action = e_html_editor_get_action (fixture->editor, action_name);
+ if (action) {
+ gtk_action_activate (action);
+ } else {
+ g_warning ("%s: Failed to find action '%s'", G_STRFUNC, action_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Expects only the part like "undo" [ ":" number ] */
+static gint
+test_utils_maybe_extract_undo_number (const gchar *command)
+{
+ const gchar *ptr;
+ gint number;
+
+ g_return_val_if_fail (command != NULL, -1);
+
+ ptr = strchr (command, ':');
+ if (!ptr)
+ return 1;
+
+ number = atoi (ptr + 1);
+ g_return_val_if_fail (number > 0, -1);
+
+ return number;
+}
+
+static const UndoContent *
+test_utils_pick_undo_content (const GSList *undo_stack,
+ gint number)
+{
+ const GSList *link;
+
+ g_return_val_if_fail (undo_stack != NULL, NULL);
+
+ for (link = undo_stack; link && number > 0; link = g_slist_next (link)) {
+ number--;
+ }
+
+ g_return_val_if_fail (link != NULL, NULL);
+ g_return_val_if_fail (link->data != NULL, NULL);
+
+ return link->data;
+}
+
+/* Each line of 'commands' contains one command.
+
+ commands = command *("\n" command)
+
+ command = actioncmd ; Execute an action
+ / modecmd ; Change editor mode to HTML or Plain Text
+ / seqcmd ; Sequence of special key strokes
+ / typecmd ; Type a text
+ / undocmd ; Undo/redo commands
+
+ actioncmd = "action:" name
+
+ actioncmd = "mode:" ("html" / "plain")
+
+ seqcmd = "seq:" sequence
+
+ sequence = "S" ; Shift key press
+ / "s" ; Shift key release
+ / "C" ; Ctrl key press
+ / "c" ; Ctrl key release
+ / "h" ; Home key press + release
+ / "e" ; End key press + release
+ / "P" ; Page-Up key press + release
+ / "p" ; Page-Down key press + release
+ / "l" ; Arrow-Left key press + release
+ / "r" ; Arrow-Right key press + release
+ / "u" ; Arrow-Up key press + release
+ / "d" ; Arrow-Down key press + release
+ / "D" ; Delete key press + release
+ / "b" ; Backspace key press + release
+ / "t" ; Tab key press + release
+ / "n" ; Return key press + release
+
+ typecmd = "type:" text ; the 'text' can contain escaped letters with a backslash, like "\\n" transforms
into "\n"
+
+ undocmd = "undo:" undotype
+
+ undotype = "undo" [ ":" number ] ; Call 'undo', number-times; if 'number' is not provided, then call it
exactly once
+ / "redo" [ ":" number ] ; Call 'redo', number-times; if 'number' is not provided, then call it
exactly once
+ / "save" ; Save current content of the editor for later tests
+ / "drop" [ ":" number ] ; Forgets saved content, if 'number' is provided, then top number saves
are forgotten
+ / "test" [ ":" number ] ; Tests current editor content against any previously saved state; the
optional
+ ; 'number' argument can be used to specify which exact previous state
to use
+ */
+gboolean
+test_utils_process_commands (TestFixture *fixture,
+ const gchar *commands)
+{
+ gchar **cmds;
+ gint cc;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (commands != NULL, FALSE);
+
+ cmds = g_strsplit (commands, "\n", -1);
+ for (cc = 0; cmds && cmds[cc] && success; cc++) {
+ const gchar *command = cmds[cc];
+
+ if (g_str_has_prefix (command, "action:")) {
+ test_utils_execute_action (fixture, command + 7);
+ } else if (g_str_has_prefix (command, "mode:")) {
+ const gchar *mode_change = command + 5;
+
+ if (g_str_equal (mode_change, "html")) {
+ test_utils_execute_action (fixture, "mode-html");
+ } else if (g_str_equal (mode_change, "plain")) {
+ test_utils_execute_action (fixture, "mode-plain");
+ } else {
+ success = FALSE;
+ g_warning ("%s: Unknown mode '%s'", G_STRFUNC, mode_change);
+ }
+ } else if (g_str_has_prefix (command, "seq:")) {
+ success = test_utils_process_sequence (fixture, command + 4);
+ } else if (g_str_has_prefix (command, "type:")) {
+ gchar *text;
+
+ text = g_strcompress (command + 5);
+ success = test_utils_type_text (fixture, text);
+ if (!success)
+ g_warning ("%s: Failed to type text '%s'", G_STRFUNC, text);
+ g_free (text);
+ } else if (g_str_has_prefix (command, "undo:")) {
+ gint number;
+
+ command += 5;
+
+ if (g_str_equal (command, "undo") || g_str_has_prefix (command, "undo:")) {
+ number = test_utils_maybe_extract_undo_number (command);
+ while (number > 0 && success) {
+ success = test_utils_execute_action (fixture, "undo");
+ number--;
+ }
+ } else if (g_str_has_prefix (command, "redo") || g_str_has_prefix (command, "redo:"))
{
+ number = test_utils_maybe_extract_undo_number (command);
+ while (number > 0 && success) {
+ success = test_utils_execute_action (fixture, "redo");
+ number--;
+ }
+ } else if (g_str_equal (command, "save")) {
+ UndoContent *uc;
+
+ uc = undo_content_new (fixture);
+ fixture->undo_stack = g_slist_prepend (fixture->undo_stack, uc);
+ } else if (g_str_equal (command, "drop") || g_str_has_prefix (command, "drop:")) {
+ number = test_utils_maybe_extract_undo_number (command);
+ g_warn_if_fail (number <= g_slist_length (fixture->undo_stack));
+
+ while (number > 0 && fixture->undo_stack) {
+ UndoContent *uc = fixture->undo_stack->data;
+
+ fixture->undo_stack = g_slist_remove (fixture->undo_stack, uc);
+ undo_content_free (uc);
+ number--;
+ }
+ } else if (g_str_equal (command, "test") || g_str_has_prefix (command, "test:")) {
+ const UndoContent *uc;
+
+ number = test_utils_maybe_extract_undo_number (command);
+ uc = test_utils_pick_undo_content (fixture->undo_stack, number);
+ success = uc && undo_content_test (fixture, uc);
+ } else {
+ g_warning ("%s: Unknown command 'undo:%s'", G_STRFUNC, command);
+ success = FALSE;
+ }
+
+ test_utils_wait_milliseconds (500);
+ } else if (*command) {
+ g_warning ("%s: Unknown command '%s'", G_STRFUNC, command);
+ success = FALSE;
+ }
+
+ test_utils_wait_milliseconds (5);
+ }
+
+ g_strfreev (cmds);
+
+ if (success) {
+ /* Give the editor some time to finish any ongoing async operations */
+ test_utils_wait_milliseconds (100);
+ }
+
+ return success;
+}
+
+gboolean
+test_utils_run_simple_test (TestFixture *fixture,
+ const gchar *commands,
+ const gchar *expected_html,
+ const gchar *expected_plain)
+{
+ EContentEditor *cnt_editor;
+ gchar *text;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (commands != NULL, FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+
+ if (!test_utils_process_commands (fixture, commands))
+ return FALSE;
+
+ if (expected_html) {
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, expected_html)) {
+ g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not
match", G_STRFUNC, text, expected_html);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+ }
+
+ if (expected_plain) {
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, expected_plain)) {
+ g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not
match", G_STRFUNC, text, expected_plain);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+ }
+
+ return TRUE;
+}
diff --git a/e-util/test-html-editor-units-utils.h b/e-util/test-html-editor-units-utils.h
new file mode 100644
index 0000000..dc1083d
--- /dev/null
+++ b/e-util/test-html-editor-units-utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TEST_HTML_EDITOR_UNITS_UTILS_H
+#define TEST_HTML_EDITOR_UNITS_UTILS_H
+
+#include <glib.h>
+#include <e-util/e-util.h>
+
+typedef struct _TestFixture {
+ GtkWidget *window;
+ EHTMLEditor *editor;
+ gboolean prompt_on_composer_mode_switch;
+
+ GSList *undo_stack; /* UndoContent * */
+} TestFixture;
+
+void test_utils_fixture_set_up (TestFixture *fixture,
+ gconstpointer user_data);
+void test_utils_fixture_tear_down (TestFixture *fixture,
+ gconstpointer user_data);
+gpointer test_utils_async_call_prepare (void);
+gboolean test_utils_async_call_wait (gpointer async_data,
+ guint timeout_seconds);
+gboolean test_utils_async_call_finish (gpointer async_data);
+gboolean test_utils_wait_milliseconds (guint milliseconds);
+
+gboolean test_utils_type_text (TestFixture *fixture,
+ const gchar *text);
+gboolean test_utils_html_equal (TestFixture *fixture,
+ const gchar *html1,
+ const gchar *html2);
+gboolean test_utils_process_commands (TestFixture *fixture,
+ const gchar *commands);
+gboolean test_utils_run_simple_test (TestFixture *fixture,
+ const gchar *commands,
+ const gchar *expected_html,
+ const gchar *expected_plain);
+
+#endif /* TEST_HTML_EDITOR_UNITS_UTILS_H */
diff --git a/e-util/test-html-editor-units.c b/e-util/test-html-editor-units.c
new file mode 100644
index 0000000..070c63d
--- /dev/null
+++ b/e-util/test-html-editor-units.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <locale.h>
+#include <e-util/e-util.h>
+
+#include "e-html-editor-private.h"
+#include "test-html-editor-units-utils.h"
+
+#define HTML_PREFIX "<html><head></head><body><p data-evo-paragraph=\"\">"
+#define HTML_SUFFIX "</p></body></html>"
+
+/* The tests do not use the 'user_data' argument, thus the functions avoid them and the typecast is needed.
*/
+typedef void (* ETestFixtureFunc) (TestFixture *fixture, gconstpointer user_data);
+
+static void
+test_create_editor (TestFixture *fixture)
+{
+ g_assert (fixture->editor != NULL);
+ g_assert_cmpstr (e_html_editor_get_content_editor_name (fixture->editor), ==,
DEFAULT_CONTENT_EDITOR_NAME);
+
+ /* test of the test function */
+ g_assert (test_utils_html_equal (fixture, "<span>a</span>", "<sPaN>a</spaN>"));
+ g_assert (!test_utils_html_equal (fixture, "<span>A</span>", "<sPaN>a</spaN>"));
+}
+
+static void
+test_style_bold_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some bold text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:bold\n",
+ HTML_PREFIX "some <b>bold</b> text" HTML_SUFFIX,
+ "some bold text"))
+ g_test_fail ();
+}
+
+static void
+test_style_bold_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:bold\n"
+ "type:bold\n"
+ "action:bold\n"
+ "type: text\n",
+ HTML_PREFIX "some <b>bold</b> text" HTML_SUFFIX,
+ "some bold text"))
+ g_test_fail ();
+}
+
+static void
+test_style_italic_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some italic text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:italic\n",
+ HTML_PREFIX "some <i>italic</i> text" HTML_SUFFIX,
+ "some italic text"))
+ g_test_fail ();
+}
+
+static void
+test_style_italic_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:italic\n"
+ "type:italic\n"
+ "action:italic\n"
+ "type: text\n",
+ HTML_PREFIX "some <i>italic</i> text" HTML_SUFFIX,
+ "some italic text"))
+ g_test_fail ();
+}
+
+static void
+test_style_underline_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some underline text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:underline\n",
+ HTML_PREFIX "some <u>underline</u> text" HTML_SUFFIX,
+ "some underline text"))
+ g_test_fail ();
+}
+
+static void
+test_style_underline_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:underline\n"
+ "type:underline\n"
+ "action:underline\n"
+ "type: text\n",
+ HTML_PREFIX "some <u>underline</u> text" HTML_SUFFIX,
+ "some underline text"))
+ g_test_fail ();
+}
+
+static void
+test_style_monospace_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some monospace text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:monospaced\n",
+ HTML_PREFIX "some <font face=\"monospace\" size=\"3\">monospace</font> text" HTML_SUFFIX,
+ "some monospace text"))
+ g_test_fail ();
+}
+
+static void
+test_style_monospace_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:monospaced\n"
+ "type:monospace\n"
+ "action:monospaced\n"
+ "type: text\n",
+ HTML_PREFIX "some <font face=\"monospace\" size=\"3\">monospace</font> text" HTML_SUFFIX,
+ "some monospace text"))
+ g_test_fail ();
+}
+
+static void
+test_undo_text_type (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "undo:save\n" /* 1 */
+ "type:some text corretC\n"
+ "undo:save\n" /* 2 */
+ "seq:CSlcsD\n" /* delete the last word */
+ "undo:save\n" /* 3 */
+ "type:broken\n" /* and write 'broken' there */
+ "undo:save\n" /* 4 */
+ "undo:undo:2\n" /* undo the 'broken' word write */
+ "undo:test:2\n"
+ "undo:redo\n" /* redo 'broken' word write */
+ "undo:test\n"
+ "undo:undo\n" /* undo 'broken' word write */
+ "undo:test:2\n"
+ "undo:redo\n" /* redo 'broken' word write */
+ "undo:test\n"
+ "undo:drop:2\n" /* 2 */
+ "undo:undo:2\n" /* undo 'broken' word write and word delete*/
+ "undo:test\n"
+ "undo:undo:3\n" /* undo text typing */
+ "undo:test\n"
+ "undo:drop\n", /* 1 */
+ HTML_PREFIX "" HTML_SUFFIX,
+ ""))
+ g_test_fail ();
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ GList *modules;
+ gint res;
+
+ setlocale (LC_ALL, "");
+
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=");
+
+ gtk_init (&argc, &argv);
+
+ e_util_init_main_thread (NULL);
+ e_passwords_init ();
+
+ modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR);
+ g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);
+
+ #define add_test(_name, _func) \
+ g_test_add (_name, TestFixture, NULL, \
+ test_utils_fixture_set_up, (ETestFixtureFunc) _func, test_utils_fixture_tear_down)
+
+ add_test ("/create/editor", test_create_editor);
+ add_test ("/style/bold-selection", test_style_bold_selection);
+ add_test ("/style/bold-typed", test_style_bold_typed);
+ add_test ("/style/italic-selection", test_style_italic_selection);
+ add_test ("/style/italic-typed", test_style_italic_typed);
+ add_test ("/style/underline-selection", test_style_underline_selection);
+ add_test ("/style/underline-typed", test_style_underline_typed);
+ add_test ("/style/monospace-selection", test_style_monospace_selection);
+ add_test ("/style/monospace-typed", test_style_monospace_typed);
+ add_test ("/undo/text-type", test_undo_text_type);
+
+ #undef add_test
+
+ res = g_test_run ();
+
+ e_util_cleanup_settings ();
+ e_spell_checker_free_global_memory ();
+
+ return res;
+}
diff --git a/modules/webkit-editor/e-webkit-editor.c b/modules/webkit-editor/e-webkit-editor.c
index 99ae870..c1eb292 100644
--- a/modules/webkit-editor/e-webkit-editor.c
+++ b/modules/webkit-editor/e-webkit-editor.c
@@ -36,6 +36,7 @@
enum {
PROP_0,
+ PROP_WEB_EXTENSION, /* for test purposes */
PROP_CAN_COPY,
PROP_CAN_CUT,
PROP_CAN_PASTE,
@@ -447,6 +448,8 @@ web_extension_proxy_created_cb (GDBusProxy *proxy,
wk_editor->priv->emit_load_finished_when_extension_is_ready = FALSE;
}
+
+ g_object_notify (G_OBJECT (wk_editor), "web-extension");
}
static void
@@ -4874,6 +4877,14 @@ webkit_editor_on_find_dialog_close (EContentEditor *editor)
webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
}
+static GDBusProxy *
+webkit_editor_get_web_extension (EWebKitEditor *editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
+
+ return editor->priv->web_extension;
+}
+
static void
webkit_editor_constructed (GObject *object)
{
@@ -5189,6 +5200,12 @@ webkit_editor_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_WEB_EXTENSION:
+ g_value_set_object (
+ value, webkit_editor_get_web_extension (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
case PROP_CAN_COPY:
g_value_set_boolean (
value, webkit_editor_can_copy (
@@ -5443,7 +5460,8 @@ webkit_editor_primary_clipboard_owner_change_cb (GtkClipboard *clipboard,
GdkEventOwnerChange *event,
EWebKitEditor *wk_editor)
{
- if (!E_IS_WEBKIT_EDITOR (wk_editor))
+ if (!E_IS_WEBKIT_EDITOR (wk_editor) ||
+ !wk_editor->priv->web_extension)
return;
if (!event->owner || !wk_editor->priv->can_copy)
@@ -5738,6 +5756,17 @@ e_webkit_editor_class_init (EWebKitEditorClass *class)
widget_class->button_press_event = webkit_editor_button_press_event;
widget_class->key_press_event = webkit_editor_key_press_event;
+ g_object_class_install_property (
+ object_class,
+ PROP_WEB_EXTENSION,
+ g_param_spec_object (
+ "web-extension",
+ "Web Extension",
+ "The Web Extension to use to talk to the WebProcess",
+ G_TYPE_DBUS_PROXY,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
g_object_class_override_property (
object_class, PROP_CAN_COPY, "can-copy");
g_object_class_override_property (
diff --git a/modules/webkit-editor/web-extension/Makefile.am b/modules/webkit-editor/web-extension/Makefile.am
index 159891d..340392b 100644
--- a/modules/webkit-editor/web-extension/Makefile.am
+++ b/modules/webkit-editor/web-extension/Makefile.am
@@ -12,6 +12,7 @@ libewebkiteditorwebextension_la_SOURCES = \
e-html-editor-selection-dom-functions.h \
e-html-editor-spell-check-dialog-dom-functions.h\
e-html-editor-table-dialog-dom-functions.h \
+ e-html-editor-test-dom-functions.h \
e-html-editor-undo-redo-manager.h \
e-html-editor-view-dom-functions.h \
e-msg-composer-dom-functions.h \
@@ -25,6 +26,7 @@ libewebkiteditorwebextension_la_SOURCES = \
e-html-editor-selection-dom-functions.c \
e-html-editor-spell-check-dialog-dom-functions.c\
e-html-editor-table-dialog-dom-functions.c \
+ e-html-editor-test-dom-functions.c \
e-html-editor-undo-redo-manager.c \
e-html-editor-view-dom-functions.c \
e-msg-composer-dom-functions.c \
diff --git a/modules/webkit-editor/web-extension/e-html-editor-test-dom-functions.c
b/modules/webkit-editor/web-extension/e-html-editor-test-dom-functions.c
new file mode 100644
index 0000000..2b231e2
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-html-editor-test-dom-functions.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-html-editor-test-dom-functions.h"
+
+gboolean
+dom_test_html_equal (WebKitDOMDocument *document,
+ const gchar *html1,
+ const gchar *html2)
+{
+ WebKitDOMElement *elem1, *elem2;
+ gboolean res = FALSE;
+ GError *error = NULL;
+
+ g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), FALSE);
+ g_return_val_if_fail (html1 != NULL, FALSE);
+ g_return_val_if_fail (html2 != NULL, FALSE);
+
+ elem1 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error);
+ if (error || !elem1) {
+ g_warning ("%s: Failed to create elem1: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ elem2 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error);
+ if (error || !elem2) {
+ g_warning ("%s: Failed to create elem2: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ webkit_dom_element_set_inner_html (elem1, html1, &error);
+ if (!error) {
+ webkit_dom_element_set_inner_html (elem2, html2, &error);
+
+ if (!error) {
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem1));
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem2));
+
+ res = webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (elem1), WEBKIT_DOM_NODE
(elem2));
+ } else {
+ g_warning ("%s: Failed to set inner html2: %s", G_STRFUNC, error->message);
+ }
+ } else {
+ g_warning ("%s: Failed to set inner html1: %s", G_STRFUNC, error->message);
+ }
+
+ g_clear_error (&error);
+
+ return res;
+}
diff --git a/modules/webkit-editor/web-extension/e-html-editor-test-dom-functions.h
b/modules/webkit-editor/web-extension/e-html-editor-test-dom-functions.h
new file mode 100644
index 0000000..3c6b273
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-html-editor-test-dom-functions.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_HTML_EDITOR_TEST_DOM_FUNCTIONS_H
+#define E_HTML_EDITOR_TEST_DOM_FUNCTIONS_H
+
+#include <webkitdom/webkitdom.h>
+
+gboolean dom_test_html_equal (WebKitDOMDocument *document,
+ const gchar *html1,
+ const gchar *html2);
+
+#endif /* E_HTML_EDITOR_TEST_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-html-editor-web-extension.c
b/modules/webkit-editor/web-extension/e-html-editor-web-extension.c
index c12e917..6596e0d 100644
--- a/modules/webkit-editor/web-extension/e-html-editor-web-extension.c
+++ b/modules/webkit-editor/web-extension/e-html-editor-web-extension.c
@@ -40,6 +40,7 @@
#include "e-html-editor-selection-dom-functions.h"
#include "e-html-editor-spell-check-dialog-dom-functions.h"
#include "e-html-editor-table-dialog-dom-functions.h"
+#include "e-html-editor-test-dom-functions.h"
#include "e-html-editor-view-dom-functions.h"
#include "e-msg-composer-dom-functions.h"
@@ -129,6 +130,15 @@ static const char introspection_xml[] =
"<!-- METHODS -->"
"<!-- ********************************************************* -->"
"<!-- ********************************************************* -->"
+"<!-- FOR TESTING ONLY -->"
+"<!-- ********************************************************* -->"
+" <method name='TestHtmlEqual'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='html1' direction='in'/>"
+" <arg type='s' name='html2' direction='in'/>"
+" <arg type='b' name='equal' direction='out'/>"
+" </method>"
+"<!-- ********************************************************* -->"
"<!-- GENERIC -->"
"<!-- ********************************************************* -->"
" <method name='ElementHasAttribute'>"
@@ -675,7 +685,22 @@ handle_method_call (GDBusConnection *connection,
if (g_strcmp0 (interface_name, E_HTML_EDITOR_WEB_EXTENSION_INTERFACE) != 0)
return;
- if (g_strcmp0 (method_name, "ElementHasAttribute") == 0) {
+ if (g_strcmp0 (method_name, "TestHtmlEqual") == 0) {
+ gboolean equal = FALSE;
+ const gchar *html1 = NULL, *html2 = NULL;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &html1, &html2);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ goto error;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ equal = dom_test_html_equal (document, html1, html2);
+
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", equal));
+ } else if (g_strcmp0 (method_name, "ElementHasAttribute") == 0) {
gboolean value = FALSE;
const gchar *element_id, *attribute;
WebKitDOMElement *element;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]