~unity-team/qtmir/no-upstart-notification

« back to all changes in this revision

Viewing changes to tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp

  • Committer: CI bot
  • Author(s): Daniel d'Andrada
  • Date: 2014-09-07 19:42:14 UTC
  • mfrom: (239.1.6 missingTouchEnd-lp1295623)
  • Revision ID: ps-jenkins@lists.canonical.com-20140907194214-1eq13l827gavf65i
QtEventFeeder: validate touches before sending them to Qt

Make sure we send a tidy touch event stream to Qt as some of it
(QQuickWindow) is vulnerable to things like missing touch releases.

Also properly ignore unsupported motion event actions such as hovering.
 Fixes: 1295623
Approved by: Gerry Boland, PS Jenkins bot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2014 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it under
 
5
 * the terms of the GNU Lesser General Public License version 3, as published by
 
6
 * the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
 
10
 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
 * Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 */
 
17
 
 
18
#include <gmock/gmock.h>
 
19
#include <gtest/gtest.h>
 
20
 
 
21
#include <qteventfeeder.h>
 
22
#include <debughelpers.h>
 
23
 
 
24
#include <QGuiApplication>
 
25
#include <QWindow>
 
26
 
 
27
#include "mock_qtwindowsystem.h"
 
28
 
 
29
using ::testing::_;
 
30
using ::testing::AllOf;
 
31
using ::testing::AnyNumber;
 
32
using ::testing::Contains;
 
33
using ::testing::AtLeast;
 
34
using ::testing::InSequence;
 
35
using ::testing::Mock;
 
36
using ::testing::SizeIs;
 
37
using ::testing::Return;
 
38
 
 
39
// own gmock extensions
 
40
using ::testing::IsPressed;
 
41
using ::testing::IsReleased;
 
42
using ::testing::HasId;
 
43
using ::testing::StateIsMoved;
 
44
 
 
45
void PrintTo(const struct QWindowSystemInterface::TouchPoint& touchPoint, ::std::ostream* os) {
 
46
    *os << "TouchPoint("
 
47
        << "id=" << touchPoint.id
 
48
        << "," << touchPointStateToString(touchPoint.state)
 
49
        << ")";
 
50
}
 
51
 
 
52
class QtEventFeederTest : public ::testing::Test {
 
53
protected:
 
54
    void SetUp() override;
 
55
    void TearDown() override;
 
56
 
 
57
    void setIrrelevantMockWindowSystemExpectations();
 
58
 
 
59
    MockQtWindowSystem *mockWindowSystem;
 
60
    QtEventFeeder *qtEventFeeder;
 
61
};
 
62
 
 
63
void QtEventFeederTest::SetUp()
 
64
{
 
65
    mockWindowSystem = new MockQtWindowSystem;
 
66
 
 
67
    EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));
 
68
 
 
69
    qtEventFeeder = new QtEventFeeder(mockWindowSystem);
 
70
 
 
71
    ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
 
72
}
 
73
 
 
74
void QtEventFeederTest::TearDown()
 
75
{
 
76
    // mockWindowSystem will be deleted by QtEventFeeder
 
77
    delete qtEventFeeder;
 
78
}
 
79
 
 
80
void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
 
81
{
 
82
    EXPECT_CALL(*mockWindowSystem, hasTargetWindow())
 
83
        .Times(AnyNumber())
 
84
        .WillRepeatedly(Return(true));
 
85
    EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())
 
86
        .Times(AnyNumber())
 
87
        .WillRepeatedly(Return(QRect(0,0,100,100)));
 
88
}
 
89
 
 
90
 
 
91
/*
 
92
   Mir sends a MirEvent([touch(id=0,state=pressed)]. QtEventFeeder happily forwards that to Qt.
 
93
 
 
94
   Then, Mir sends a MirEvent([touch(id=1,state=pressed)]). In MirEvents, every single active touch
 
95
   point must be listed in the event even if it didn't change at all in the meantime. So that's a bug.
 
96
   But instead of crashing or forwarding the bogus event stream down to Qt, QtEventFeeder should attempt
 
97
   to fix the situation by synthesizing a touch[id=1,state=released] to be send along with the
 
98
   touch(id=1,state=pressed) it got. So that Qt receives a correct touch event stream.
 
99
 */
 
100
TEST_F(QtEventFeederTest, GenerateMissingTouchEnd)
 
101
{
 
102
 
 
103
    setIrrelevantMockWindowSystemExpectations();
 
104
 
 
105
    EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
 
106
                                                              Contains(AllOf(HasId(0),
 
107
                                                                             IsPressed()))),_)).Times(1);
 
108
 
 
109
    MirEvent mirEvent;
 
110
    mirEvent.type = mir_event_type_motion;
 
111
    mirEvent.motion.pointer_count = 1;
 
112
    mirEvent.motion.pointer_coordinates[0].id = 0;
 
113
    mirEvent.motion.pointer_coordinates[0].x = 10;
 
114
    mirEvent.motion.pointer_coordinates[0].y = 10;
 
115
    mirEvent.motion.pointer_coordinates[0].touch_major = 1;
 
116
    mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
 
117
    mirEvent.motion.pointer_coordinates[0].pressure = 10;
 
118
    mirEvent.motion.action = mir_motion_action_down;
 
119
    mirEvent.motion.event_time = 123 * 1000000;
 
120
 
 
121
    qtEventFeeder->dispatch(mirEvent);
 
122
 
 
123
    ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
 
124
 
 
125
    setIrrelevantMockWindowSystemExpectations();
 
126
 
 
127
    EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(2),
 
128
                                                              Contains(AllOf(HasId(0),IsReleased())),
 
129
                                                              Contains(AllOf(HasId(1),IsPressed()))
 
130
                                                             ),_)).Times(1);
 
131
 
 
132
    mirEvent.type = mir_event_type_motion;
 
133
    mirEvent.motion.pointer_count = 1;
 
134
    mirEvent.motion.pointer_coordinates[0].id = 1;
 
135
    mirEvent.motion.pointer_coordinates[0].x = 20;
 
136
    mirEvent.motion.pointer_coordinates[0].y = 20;
 
137
    mirEvent.motion.pointer_coordinates[0].touch_major = 1;
 
138
    mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
 
139
    mirEvent.motion.pointer_coordinates[0].pressure = 10;
 
140
    mirEvent.motion.action = mir_motion_action_down;
 
141
    mirEvent.motion.event_time = 125 * 1000000;
 
142
 
 
143
    qtEventFeeder->dispatch(mirEvent);
 
144
 
 
145
    ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
 
146
}
 
147
 
 
148
TEST_F(QtEventFeederTest, PressSameTouchTwice)
 
149
{
 
150
    setIrrelevantMockWindowSystemExpectations();
 
151
 
 
152
    EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
 
153
                                                              Contains(AllOf(HasId(0),
 
154
                                                                             IsPressed()))),_)).Times(1);
 
155
 
 
156
    MirEvent mirEvent;
 
157
    mirEvent.type = mir_event_type_motion;
 
158
    mirEvent.motion.pointer_count = 1;
 
159
    mirEvent.motion.pointer_coordinates[0].id = 0;
 
160
    mirEvent.motion.pointer_coordinates[0].x = 10;
 
161
    mirEvent.motion.pointer_coordinates[0].y = 10;
 
162
    mirEvent.motion.pointer_coordinates[0].touch_major = 1;
 
163
    mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
 
164
    mirEvent.motion.pointer_coordinates[0].pressure = 10;
 
165
    mirEvent.motion.action = mir_motion_action_down;
 
166
    mirEvent.motion.event_time = 123 * 1000000;
 
167
 
 
168
    qtEventFeeder->dispatch(mirEvent);
 
169
 
 
170
    ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
 
171
 
 
172
    setIrrelevantMockWindowSystemExpectations();
 
173
 
 
174
    EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
 
175
                                                              Contains(AllOf(HasId(0), StateIsMoved()))
 
176
                                                             ),_)).Times(1);
 
177
 
 
178
    mirEvent.type = mir_event_type_motion;
 
179
    mirEvent.motion.pointer_count = 1;
 
180
    mirEvent.motion.pointer_coordinates[0].id = 0;
 
181
    mirEvent.motion.pointer_coordinates[0].x = 20;
 
182
    mirEvent.motion.pointer_coordinates[0].y = 20;
 
183
    mirEvent.motion.pointer_coordinates[0].touch_major = 1;
 
184
    mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
 
185
    mirEvent.motion.pointer_coordinates[0].pressure = 10;
 
186
    mirEvent.motion.action = mir_motion_action_down;
 
187
    mirEvent.motion.event_time = 125 * 1000000;
 
188
 
 
189
    qtEventFeeder->dispatch(mirEvent);
 
190
 
 
191
    ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
 
192
}
 
193
 
 
194
TEST_F(QtEventFeederTest, IgnoreHovering)
 
195
{
 
196
    setIrrelevantMockWindowSystemExpectations();
 
197
    EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,_)).Times(0);
 
198
 
 
199
    MirEvent mirEvent;
 
200
    mirEvent.type = mir_event_type_motion;
 
201
    mirEvent.motion.pointer_count = 1;
 
202
    mirEvent.motion.pointer_coordinates[0].id = 0;
 
203
    mirEvent.motion.pointer_coordinates[0].x = 10;
 
204
    mirEvent.motion.pointer_coordinates[0].y = 10;
 
205
    mirEvent.motion.pointer_coordinates[0].touch_major = 1;
 
206
    mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
 
207
    mirEvent.motion.pointer_coordinates[0].pressure = 10;
 
208
    mirEvent.motion.action = mir_motion_action_hover_enter;
 
209
    mirEvent.motion.event_time = 123 * 1000000;
 
210
 
 
211
    qtEventFeeder->dispatch(mirEvent);
 
212
 
 
213
    mirEvent.motion.pointer_coordinates[0].x = 20;
 
214
    mirEvent.motion.pointer_coordinates[0].y = 20;
 
215
    mirEvent.motion.action = mir_motion_action_hover_move;
 
216
    mirEvent.motion.event_time = 125 * 1000000;
 
217
 
 
218
    qtEventFeeder->dispatch(mirEvent);
 
219
 
 
220
    mirEvent.motion.action = mir_motion_action_hover_exit;
 
221
    mirEvent.motion.event_time = 127 * 1000000;
 
222
 
 
223
    qtEventFeeder->dispatch(mirEvent);
 
224
}