Skip to content

Commit 4fb731d

Browse files
committed
[GTK] Add unit tests for GtkInputMethodFilter
https://bugs.webkit.org/show_bug.cgi?id=88698 Reviewed by Carlos Garcia Campos. Add unit tests for GtkInputMethodFilter in the WebCore platform layer. This change adds the TestGtk test suite which will be used for all non-API layer GTK unit tests. * TestWebKitAPI/GNUmakefile.am: Update the build to include the new tests. * TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp: Added. (TestWebKitAPI::PlatformWebView::PlatformWebView): Remove the call to gtk_init here as it's now in main.cpp. * TestWebKitAPI/gtk/main.cpp: Change the g_type_init call to gtk_init, because now a majority of all unit tests depend on GTK+ being initialized. Canonical link: https://commits.webkit.org/108042@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@121475 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 09cd30e commit 4fb731d

File tree

5 files changed

+356
-5
lines changed

5 files changed

+356
-5
lines changed

Tools/ChangeLog

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
2012-06-28 Martin Robinson <[email protected]>
2+
3+
[GTK] Add unit tests for GtkInputMethodFilter
4+
https://bugs.webkit.org/show_bug.cgi?id=88698
5+
6+
Reviewed by Carlos Garcia Campos.
7+
8+
Add unit tests for GtkInputMethodFilter in the WebCore platform layer.
9+
This change adds the TestGtk test suite which will be used for all non-API
10+
layer GTK unit tests.
11+
12+
* TestWebKitAPI/GNUmakefile.am: Update the build to include the new tests.
13+
* TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp: Added.
14+
(TestWebKitAPI::PlatformWebView::PlatformWebView): Remove the call to gtk_init here
15+
as it's now in main.cpp.
16+
* TestWebKitAPI/gtk/main.cpp: Change the g_type_init call to gtk_init, because now
17+
a majority of all unit tests depend on GTK+ being initialized.
18+
119
2012-06-28 Christophe Dumez <[email protected]>
220

321
[EFL] Enable support for HTML5 datalist

Tools/TestWebKitAPI/GNUmakefile.am

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ Libraries_libTestWebKitAPIMain_la_CPPFLAGS = \
2424
-I$(top_builddir)/DerivedSources/WebKit2/include \
2525
$(global_cppflags) \
2626
$(javascriptcore_cppflags) \
27-
$(GLIB_CFLAGS)
27+
$(GLIB_CFLAGS) \
28+
$(GTK_CFLAGS)
2829

2930
noinst_PROGRAMS += \
3031
Programs/TestWebKitAPI/TestWTF
3132

3233
Programs_TestWebKitAPI_TestWTF_CPPFLAGS = \
3334
$(Libraries_libTestWebKitAPIMain_la_CPPFLAGS) \
3435
$(GLIB_LIBS) \
35-
$(GTK_CFLAGS) \
3636
$(CAIRO_CFLAGS) \
3737
$(LIBSOUP_CFLAGS)
3838

@@ -62,6 +62,32 @@ Programs_TestWebKitAPI_TestWTF_SOURCES = \
6262
Tools/TestWebKitAPI/Tests/WTF/VectorReverse.cpp \
6363
Tools/TestWebKitAPI/WTFStringUtilities.h
6464

65+
noinst_PROGRAMS += \
66+
Programs/TestWebKitAPI/TestGtk
67+
68+
Programs_TestWebKitAPI_TestGtk_CPPFLAGS = \
69+
$(Programs_TestWebKitAPI_TestWTF_CPPFLAGS) \
70+
$(webcore_cppflags) \
71+
$(webcoregtk_cppflags) \
72+
$(CAIRO_CFLAGS) \
73+
$(LIBSOUP_CFLAGS)
74+
75+
Programs_TestWebKitAPI_TestGtk_LDADD = \
76+
$(Programs_TestWebKitAPI_TestWTF_LDADD) \
77+
libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@[email protected] \
78+
libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@[email protected]
79+
80+
Programs_TestWebKitAPI_TestGtk_LDFLAGS = \
81+
$(Programs_TestWebKitAPI_TestWTF_LDFLAGS)
82+
83+
Programs_TestWebKitAPI_TestGtk_SOURCES = \
84+
Source/WebCore/platform/graphics/IntRect.cpp \
85+
Source/WebCore/platform/graphics/cairo/IntRectCairo.cpp \
86+
Source/WebCore/platform/graphics/gtk/IntRectGtk.cpp \
87+
Source/WebCore/platform/gtk/GtkInputMethodFilter.cpp \
88+
Tools/TestWebKitAPI/config.h \
89+
Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp
90+
6591
if ENABLE_WEBKIT2
6692
noinst_PROGRAMS += \
6793
Programs/TestWebKitAPI/TestWebKit2
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
/*
2+
* Copyright (C) 2012 Igalia S.L.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
* THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#include "config.h"
27+
28+
#include "GtkInputMethodFilter.h"
29+
#include "WTFStringUtilities.h"
30+
#include <gtk/gtk.h>
31+
#include <wtf/gobject/GOwnPtr.h>
32+
#include <wtf/gobject/GRefPtr.h>
33+
#include <wtf/text/CString.h>
34+
35+
using namespace WebCore;
36+
37+
namespace TestWebKitAPI {
38+
39+
class TestInputMethodFilter : public GtkInputMethodFilter {
40+
public:
41+
TestInputMethodFilter()
42+
: m_testWindow(gtk_window_new(GTK_WINDOW_POPUP))
43+
{
44+
gtk_widget_show(m_testWindow.get());
45+
setWidget(m_testWindow.get());
46+
47+
// Focus in is necessary to activate the default input method in the multicontext.
48+
notifyFocusedIn();
49+
}
50+
51+
Vector<String>& events() { return m_events; }
52+
53+
void sendKeyEventToFilter(unsigned int gdkKeyValue, GdkEventType type, unsigned int modifiers = 0)
54+
{
55+
GdkEvent* event = gdk_event_new(type);
56+
event->key.keyval = gdkKeyValue;
57+
event->key.state = modifiers;
58+
event->key.window = gtk_widget_get_window(m_testWindow.get());
59+
event->key.time = GDK_CURRENT_TIME;
60+
g_object_ref(event->key.window);
61+
62+
#ifndef GTK_API_VERSION_2
63+
gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default())));
64+
#endif
65+
66+
GOwnPtr<GdkKeymapKey> keys;
67+
gint nKeys;
68+
if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeyValue, &keys.outPtr(), &nKeys))
69+
event->key.hardware_keycode = keys.get()[0].keycode;
70+
71+
filterKeyEvent(&event->key);
72+
gdk_event_free(event);
73+
}
74+
75+
void sendPressAndReleaseKeyEventPairToFilter(unsigned int gdkKeyValue, unsigned int modifiers = 0)
76+
{
77+
sendKeyEventToFilter(gdkKeyValue, GDK_KEY_PRESS, modifiers);
78+
sendKeyEventToFilter(gdkKeyValue, GDK_KEY_RELEASE, modifiers);
79+
}
80+
81+
protected:
82+
virtual bool sendSimpleKeyEvent(GdkEventKey* event, WTF::String eventString)
83+
{
84+
const char* eventType = event->type == GDK_KEY_RELEASE ? "release" : "press";
85+
if (!eventString.isNull())
86+
m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x text='%s'", eventType, event->keyval, eventString.utf8().data()));
87+
else
88+
m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x", eventType, event->keyval));
89+
90+
return true;
91+
}
92+
93+
virtual bool sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend)
94+
{
95+
const char* eventType = event->type == GDK_KEY_RELEASE ? "release" : "press";
96+
m_events.append(String::format("sendKeyEventWithCompositionResults type=%s keycode=%u", eventType, event->keyval));
97+
98+
if (resultsToSend & Composition && !m_confirmedComposition.isNull())
99+
confirmCompositionText(m_confirmedComposition);
100+
if (resultsToSend & Preedit && !m_preedit.isNull())
101+
setPreedit(m_preedit, m_cursorOffset);
102+
103+
return true;
104+
}
105+
106+
virtual bool canEdit()
107+
{
108+
return true;
109+
}
110+
111+
virtual void confirmCompositionText(String text)
112+
{
113+
m_events.append(String::format("confirmComposition '%s'", text.utf8().data()));
114+
}
115+
116+
virtual void confirmCurrentComposition()
117+
{
118+
m_events.append(String("confirmCurrentcomposition"));
119+
}
120+
121+
virtual void cancelCurrentComposition()
122+
{
123+
m_events.append(String("cancelCurrentComposition"));
124+
}
125+
126+
virtual void setPreedit(String preedit, int cursorOffset)
127+
{
128+
m_events.append(String::format("setPreedit text='%s' cursorOffset=%i", preedit.utf8().data(), cursorOffset));
129+
}
130+
131+
private:
132+
GRefPtr<GtkWidget> m_testWindow;
133+
Vector<String> m_events;
134+
};
135+
136+
TEST(GTK, GtkInputMethodFilterSimple)
137+
{
138+
TestInputMethodFilter inputMethodFilter;
139+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_g);
140+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_t);
141+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_k);
142+
143+
const Vector<String>& events = inputMethodFilter.events();
144+
145+
ASSERT_EQ(6, events.size());
146+
ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=67 text='g'"), events[0]);
147+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=67"), events[1]);
148+
ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=74 text='t'"), events[2]);
149+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=74"), events[3]);
150+
ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=6b text='k'"), events[4]);
151+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=6b"), events[5]);
152+
}
153+
154+
TEST(GTK, GtkInputMethodFilterUnicodeSequence)
155+
{
156+
TestInputMethodFilter inputMethodFilter;
157+
158+
// This is simple unicode hex entry of the characters, u, 0, 0, f, 4 pressed with
159+
// the shift and controls keys held down. In reality, these values are not typical
160+
// of an actual hex entry, because they'd be transformed by the shift modifier according
161+
// to the keyboard layout. For instance, on a US keyboard a 0 with the shift key pressed
162+
// is a right parenthesis. Using these values prevents having to work out what the
163+
// transformed characters are based on the current keyboard layout.
164+
inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Control_L, GDK_KEY_PRESS);
165+
inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Shift_L, GDK_KEY_PRESS, GDK_CONTROL_MASK);
166+
167+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_U, GDK_SHIFT_MASK | GDK_CONTROL_MASK);
168+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_0, GDK_SHIFT_MASK | GDK_CONTROL_MASK);
169+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_0, GDK_SHIFT_MASK | GDK_CONTROL_MASK);
170+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_F, GDK_SHIFT_MASK | GDK_CONTROL_MASK);
171+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_4, GDK_SHIFT_MASK | GDK_CONTROL_MASK);
172+
173+
inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Shift_L, GDK_KEY_RELEASE, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
174+
inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Control_L, GDK_KEY_RELEASE, GDK_CONTROL_MASK);
175+
176+
const Vector<String>& events = inputMethodFilter.events();
177+
ASSERT_EQ(21, events.size());
178+
ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=ffe3"), events[0]);
179+
ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=ffe1"), events[1]);
180+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=85"), events[2]);
181+
ASSERT_EQ(String("setPreedit text='u' cursorOffset=1"), events[3]);
182+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=55"), events[4]);
183+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=48"), events[5]);
184+
ASSERT_EQ(String("setPreedit text='u0' cursorOffset=2"), events[6]);
185+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=30"), events[7]);
186+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=48"), events[8]);
187+
ASSERT_EQ(String("setPreedit text='u00' cursorOffset=3"), events[9]);
188+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=30"), events[10]);
189+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=70"), events[11]);
190+
ASSERT_EQ(String("setPreedit text='u00F' cursorOffset=4"), events[12]);
191+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=46"), events[13]);
192+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=52"), events[14]);
193+
ASSERT_EQ(String("setPreedit text='u00F4' cursorOffset=5"), events[15]);
194+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=34"), events[16]);
195+
ASSERT_EQ(String("confirmComposition 'ô'"), events[17]);
196+
ASSERT_EQ(String("setPreedit text='' cursorOffset=0"), events[18]);
197+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffe1"), events[19]);
198+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffe3"), events[20]);
199+
}
200+
201+
TEST(GTK, GtkInputMethodFilterComposeKey)
202+
{
203+
TestInputMethodFilter inputMethodFilter;
204+
205+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_Multi_key);
206+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_apostrophe);
207+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_o);
208+
209+
const Vector<String>& events = inputMethodFilter.events();
210+
ASSERT_EQ(5, events.size());
211+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=39"), events[0]);
212+
ASSERT_EQ(String("setPreedit text='' cursorOffset=0"), events[1]);
213+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=27"), events[2]);
214+
ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=6f text='ó'"), events[3]);
215+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=6f"), events[4]);
216+
}
217+
218+
typedef void (*GetPreeditStringCallback) (GtkIMContext*, gchar**, PangoAttrList**, int*);
219+
static void temporaryGetPreeditStringOverride(GtkIMContext*, char** string, PangoAttrList** attrs, int* cursorPosition)
220+
{
221+
*string = g_strdup("preedit of doom, bringer of cheese");
222+
*cursorPosition = 3;
223+
}
224+
225+
TEST(GTK, GtkInputMethodFilterContextEventsWithoutKeyEvents)
226+
{
227+
TestInputMethodFilter inputMethodFilter;
228+
229+
// This is a bit of a hack to avoid mocking out the entire InputMethodContext, by
230+
// simply replacing the get_preedit_string virtual method for the length of this test.
231+
GtkIMContext* context = inputMethodFilter.context();
232+
GtkIMContextClass* contextClass = GTK_IM_CONTEXT_GET_CLASS(context);
233+
GetPreeditStringCallback previousCallback = contextClass->get_preedit_string;
234+
contextClass->get_preedit_string = temporaryGetPreeditStringOverride;
235+
236+
g_signal_emit_by_name(context, "preedit-changed");
237+
g_signal_emit_by_name(context, "commit", "commit text");
238+
239+
contextClass->get_preedit_string = previousCallback;
240+
241+
const Vector<String>& events = inputMethodFilter.events();
242+
ASSERT_EQ(6, events.size());
243+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215"), events[0]);
244+
ASSERT_EQ(String("setPreedit text='preedit of doom, bringer of cheese' cursorOffset=3"), events[1]);
245+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff"), events[2]);
246+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215"), events[3]);
247+
ASSERT_EQ(String("confirmComposition 'commit text'"), events[4]);
248+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff"), events[5]);
249+
}
250+
251+
static bool gSawContextReset = false;
252+
typedef void (*ResetCallback) (GtkIMContext*);
253+
static void temporaryResetOverride(GtkIMContext*)
254+
{
255+
gSawContextReset = true;
256+
}
257+
258+
static void verifyCanceledComposition(const Vector<String>& events)
259+
{
260+
ASSERT_EQ(4, events.size());
261+
ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=39"), events[0]);
262+
ASSERT_EQ(String("setPreedit text='' cursorOffset=0"), events[1]);
263+
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=27"), events[2]);
264+
ASSERT_EQ(String("confirmCurrentcomposition"), events[3]);
265+
ASSERT(gSawContextReset);
266+
}
267+
268+
TEST(GTK, GtkInputMethodFilterContextFocusOutDuringOngoingComposition)
269+
{
270+
TestInputMethodFilter inputMethodFilter;
271+
272+
// See comment above about this technique.
273+
GtkIMContext* context = inputMethodFilter.context();
274+
GtkIMContextClass* contextClass = GTK_IM_CONTEXT_GET_CLASS(context);
275+
ResetCallback previousCallback = contextClass->reset;
276+
contextClass->reset = temporaryResetOverride;
277+
278+
gSawContextReset = false;
279+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_Multi_key);
280+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_apostrophe);
281+
inputMethodFilter.notifyFocusedOut();
282+
283+
verifyCanceledComposition(inputMethodFilter.events());
284+
285+
contextClass->reset = previousCallback;
286+
}
287+
288+
TEST(GTK, GtkInputMethodFilterContextMouseClickDuringOngoingComposition)
289+
{
290+
TestInputMethodFilter inputMethodFilter;
291+
292+
// See comment above about this technique.
293+
GtkIMContext* context = inputMethodFilter.context();
294+
GtkIMContextClass* contextClass = GTK_IM_CONTEXT_GET_CLASS(context);
295+
ResetCallback previousCallback = contextClass->reset;
296+
contextClass->reset = temporaryResetOverride;
297+
298+
gSawContextReset = false;
299+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_Multi_key);
300+
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_apostrophe);
301+
inputMethodFilter.notifyMouseButtonPress();
302+
303+
verifyCanceledComposition(inputMethodFilter.events());
304+
305+
contextClass->reset = previousCallback;
306+
}
307+
308+
} // namespace TestWebKitAPI

Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ namespace TestWebKitAPI {
3434

3535
PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
3636
{
37-
gtk_init(0, 0);
3837
m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3938
m_view = WKViewCreate(contextRef, pageGroupRef);
4039
gtk_container_add(GTK_CONTAINER(m_window), GTK_WIDGET(m_view));

0 commit comments

Comments
 (0)