summaryrefslogtreecommitdiffstats
path: root/ui/events/event_rewriter_unittest.cc
blob: 61557bcdbe010096ec42da9439679b978c0f2c6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/event_rewriter.h"

#include <list>
#include <map>
#include <set>
#include <utility>

#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/test/test_event_processor.h"

namespace ui {

namespace {

// To test the handling of |EventRewriter|s through |EventSource|,
// we rewrite and test event types.
class TestEvent : public Event {
 public:
  explicit TestEvent(EventType type)
      : Event(type, base::TimeDelta(), 0), unique_id_(next_unique_id_++) {}
  ~TestEvent() override {}
  int unique_id() const { return unique_id_; }

 private:
  static int next_unique_id_;
  int unique_id_;
};

int TestEvent::next_unique_id_ = 0;

// TestEventRewriteProcessor is set up with a sequence of event types,
// and fails if the events received via OnEventFromSource() do not match
// this sequence. These expected event types are consumed on receipt.
class TestEventRewriteProcessor : public test::TestEventProcessor {
 public:
  TestEventRewriteProcessor() {}
  ~TestEventRewriteProcessor() override { CheckAllReceived(); }

  void AddExpectedEvent(EventType type) { expected_events_.push_back(type); }
  // Test that all expected events have been received.
  void CheckAllReceived() { EXPECT_TRUE(expected_events_.empty()); }

  // EventProcessor:
  EventDispatchDetails OnEventFromSource(Event* event) override {
    EXPECT_FALSE(expected_events_.empty());
    EXPECT_EQ(expected_events_.front(), event->type());
    expected_events_.pop_front();
    return EventDispatchDetails();
  }

 private:
  std::list<EventType> expected_events_;
  DISALLOW_COPY_AND_ASSIGN(TestEventRewriteProcessor);
};

// Trivial EventSource that does nothing but send events.
class TestEventRewriteSource : public EventSource {
 public:
  explicit TestEventRewriteSource(EventProcessor* processor)
      : processor_(processor) {}
  EventProcessor* GetEventProcessor() override { return processor_; }
  void Send(EventType type) {
    scoped_ptr<Event> event(new TestEvent(type));
    (void)SendEventToProcessor(event.get());
  }

 private:
  EventProcessor* processor_;
};

// This EventRewriter always returns the same status, and if rewriting, the
// same event type; it is used to test simple rewriting, and rewriter addition,
// removal, and sequencing. Consequently EVENT_REWRITE_DISPATCH_ANOTHER is not
// supported here (calls to NextDispatchEvent() would continue indefinitely).
class TestConstantEventRewriter : public EventRewriter {
 public:
  TestConstantEventRewriter(EventRewriteStatus status, EventType type)
      : status_(status), type_(type) {
    CHECK_NE(EVENT_REWRITE_DISPATCH_ANOTHER, status);
  }

  EventRewriteStatus RewriteEvent(const Event& event,
                                  scoped_ptr<Event>* rewritten_event) override {
    if (status_ == EVENT_REWRITE_REWRITTEN)
      rewritten_event->reset(new TestEvent(type_));
    return status_;
  }
  EventRewriteStatus NextDispatchEvent(const Event& last_event,
                                       scoped_ptr<Event>* new_event) override {
    NOTREACHED();
    return status_;
  }

 private:
  EventRewriteStatus status_;
  EventType type_;
};

// This EventRewriter runs a simple state machine; it is used to test
// EVENT_REWRITE_DISPATCH_ANOTHER.
class TestStateMachineEventRewriter : public EventRewriter {
 public:
  TestStateMachineEventRewriter() : last_rewritten_event_(0), state_(0) {}
  void AddRule(int from_state, EventType from_type,
               int to_state, EventType to_type, EventRewriteStatus to_status) {
    RewriteResult r = {to_state, to_type, to_status};
    rules_.insert(std::pair<RewriteCase, RewriteResult>(
        RewriteCase(from_state, from_type), r));
  }
  EventRewriteStatus RewriteEvent(const Event& event,
                                  scoped_ptr<Event>* rewritten_event) override {
    RewriteRules::iterator find =
        rules_.find(RewriteCase(state_, event.type()));
    if (find == rules_.end())
      return EVENT_REWRITE_CONTINUE;
    if ((find->second.status == EVENT_REWRITE_REWRITTEN) ||
        (find->second.status == EVENT_REWRITE_DISPATCH_ANOTHER)) {
      last_rewritten_event_ = new TestEvent(find->second.type);
      rewritten_event->reset(last_rewritten_event_);
    } else {
      last_rewritten_event_ = 0;
    }
    state_ = find->second.state;
    return find->second.status;
  }
  EventRewriteStatus NextDispatchEvent(const Event& last_event,
                                       scoped_ptr<Event>* new_event) override {
    EXPECT_TRUE(last_rewritten_event_);
    const TestEvent* arg_last = static_cast<const TestEvent*>(&last_event);
    EXPECT_EQ(last_rewritten_event_->unique_id(), arg_last->unique_id());
    const TestEvent* arg_new = static_cast<const TestEvent*>(new_event->get());
    EXPECT_FALSE(arg_new && arg_last->unique_id() == arg_new->unique_id());
    return RewriteEvent(last_event, new_event);
  }

 private:
  typedef std::pair<int, EventType> RewriteCase;
  struct RewriteResult {
    int state;
    EventType type;
    EventRewriteStatus status;
  };
  typedef std::map<RewriteCase, RewriteResult> RewriteRules;
  RewriteRules rules_;
  TestEvent* last_rewritten_event_;
  int state_;
};

}  // namespace

TEST(EventRewriterTest, EventRewriting) {
  // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
  // it is placed at the beginning of the chain and later removed,
  // to verify that rewriter removal works.
  TestConstantEventRewriter r0(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);

  // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
  // it is placed at the beginning of the chain to verify that a
  // later rewriter sees the events.
  TestConstantEventRewriter r1(EVENT_REWRITE_CONTINUE, ET_UNKNOWN);

  // TestEventRewriter r2 has a state machine, primarily to test
  // |EVENT_REWRITE_DISPATCH_ANOTHER|.
  TestStateMachineEventRewriter r2;

  // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
  // it is placed at the end of the chain to verify that previously
  // rewritten events are not passed further down the chain.
  TestConstantEventRewriter r3(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);

  TestEventRewriteProcessor p;
  TestEventRewriteSource s(&p);
  s.AddEventRewriter(&r0);
  s.AddEventRewriter(&r1);
  s.AddEventRewriter(&r2);

  // These events should be rewritten by r0 to ET_CANCEL_MODE.
  p.AddExpectedEvent(ET_CANCEL_MODE);
  s.Send(ET_MOUSE_DRAGGED);
  p.AddExpectedEvent(ET_CANCEL_MODE);
  s.Send(ET_MOUSE_PRESSED);
  p.CheckAllReceived();

  // Remove r0, and verify that it's gone and that events make it through.
  s.AddEventRewriter(&r3);
  s.RemoveEventRewriter(&r0);
  r2.AddRule(0, ET_SCROLL_FLING_START,
             0, ET_SCROLL_FLING_CANCEL, EVENT_REWRITE_REWRITTEN);
  p.AddExpectedEvent(ET_SCROLL_FLING_CANCEL);
  s.Send(ET_SCROLL_FLING_START);
  p.CheckAllReceived();
  s.RemoveEventRewriter(&r3);

  // Verify EVENT_REWRITE_DISPATCH_ANOTHER using a state machine
  // (that happens to be analogous to sticky keys).
  r2.AddRule(0, ET_KEY_PRESSED,
             1, ET_KEY_PRESSED, EVENT_REWRITE_CONTINUE);
  r2.AddRule(1, ET_MOUSE_PRESSED,
             0, ET_MOUSE_PRESSED, EVENT_REWRITE_CONTINUE);
  r2.AddRule(1, ET_KEY_RELEASED,
             2, ET_KEY_RELEASED, EVENT_REWRITE_DISCARD);
  r2.AddRule(2, ET_MOUSE_RELEASED,
             3, ET_MOUSE_RELEASED, EVENT_REWRITE_DISPATCH_ANOTHER);
  r2.AddRule(3, ET_MOUSE_RELEASED,
             0, ET_KEY_RELEASED, EVENT_REWRITE_REWRITTEN);
  p.AddExpectedEvent(ET_KEY_PRESSED);
  s.Send(ET_KEY_PRESSED);
  s.Send(ET_KEY_RELEASED);
  p.AddExpectedEvent(ET_MOUSE_PRESSED);
  s.Send(ET_MOUSE_PRESSED);

  // Removing rewriters r1 and r3 shouldn't affect r2.
  s.RemoveEventRewriter(&r1);
  s.RemoveEventRewriter(&r3);

  // Continue with the state-based rewriting.
  p.AddExpectedEvent(ET_MOUSE_RELEASED);
  p.AddExpectedEvent(ET_KEY_RELEASED);
  s.Send(ET_MOUSE_RELEASED);
  p.CheckAllReceived();
}

}  // namespace ui