Index: ui/chromeos/touch_exploration_controller_unittest.cc |
diff --git a/ui/chromeos/touch_exploration_controller_unittest.cc b/ui/chromeos/touch_exploration_controller_unittest.cc |
index 10da4b1f3a7f5a272d86d88d1a10daae2f1d1e22..fcf0bb20f9c730b5b20b778a09b9cbe6c97ff849 100644 |
--- a/ui/chromeos/touch_exploration_controller_unittest.cc |
+++ b/ui/chromeos/touch_exploration_controller_unittest.cc |
@@ -13,6 +13,7 @@ |
#include "ui/aura/window.h" |
#include "ui/events/event.h" |
#include "ui/events/event_utils.h" |
+#include "ui/events/test/events_test_utils.h" |
#include "ui/gfx/geometry/point.h" |
#include "ui/gl/gl_implementation.h" |
#include "ui/gl/gl_surface.h" |
@@ -57,6 +58,16 @@ class EventCapturer : public ui::EventHandler { |
DISALLOW_COPY_AND_ASSIGN(EventCapturer); |
}; |
+int Factorial(int n) { |
+ if (n <= 0) |
+ return 0; |
+ if (n == 1) |
+ return 1; |
+ if (n == 2) |
+ return 2; |
+ return n * Factorial(n - 1); |
+} |
+ |
} // namespace |
class TouchExplorationTest : public aura::test::AuraTestBase { |
@@ -948,4 +959,86 @@ TEST_F(TouchExplorationTest, Passthrough) { |
EXPECT_TRUE(IsInNoFingersDownState()); |
} |
+TEST_F(TouchExplorationTest, AllFingerPermutations) { |
+ SwitchTouchExplorationMode(true); |
+ |
+ // We will test all permutations of events from three different fingers |
+ // to ensure that we return to NO_FINGERS_DOWN when fingers have been |
+ // released. |
+ ScopedVector<ui::TouchEvent> all_events; |
+ all_events.push_back( |
aboxhall
2014/06/27 18:08:02
This could be a for-loop over touch_id - it'd also
evy
2014/06/27 21:00:03
Done. Great idea.
|
+ new TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(11, 12), 0, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_MOVED, gfx::Point(13, 14), 0, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(15, 16), 0, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(21, 22), 1, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_MOVED, gfx::Point(23, 24), 1, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(25, 26), 1, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(31, 32), 2, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_MOVED, gfx::Point(33, 34), 2, Now())); |
+ all_events.push_back( |
+ new TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(35, 36), 2, Now())); |
+ |
+ const int num_events = all_events.size(); |
+ const int num_permutations = Factorial(num_events); |
+ |
+ for (int i = 0; i < num_permutations; i++) { |
aboxhall
2014/06/27 18:08:02
Since this is not used as a simple index on the ne
evy
2014/06/27 21:00:03
Done.
|
+ std::vector<ui::TouchEvent*> queued_events = all_events.get(); |
+ std::vector<bool> fingers_pressed(3, false); |
aboxhall
2014/06/27 18:08:01
My favourite vector constructor!
evy
2014/06/27 21:00:03
:D
|
+ // current_factorial starts at factorial(num_events - 1) |
+ // and decreases each iteration |
+ int current_factorial = num_permutations/num_events; |
+ for (int j = num_events - 1; j >= 0; j--) { |
aboxhall
2014/06/27 18:08:02
I can't fully understand this code (just the bit a
evy
2014/06/27 21:00:03
I renamed some variables and added tons of comment
|
+ int index; |
+ if (j == num_events - 1) { |
aboxhall
2014/06/27 18:08:02
This could be a switch statement (and you could pu
evy
2014/06/27 21:00:03
I'm not sure if this comment applies - can you rea
|
+ index = i / current_factorial; |
+ current_factorial /= j; |
+ } else if (j == 0) { |
+ index = 0; |
+ } else { |
+ index = (i % (current_factorial * (j + 1)) / current_factorial); |
+ current_factorial /= j; |
+ } |
+ ui::TouchEvent* next_dispatch = queued_events[index]; |
+ ASSERT_TRUE(next_dispatch != NULL); |
+ EventTestApi test_dispatch(next_dispatch); |
+ test_dispatch.set_time_stamp(Now()); |
+ generator_->Dispatch(next_dispatch); |
+ queued_events.erase(queued_events.begin() + index); |
+ // Note: it is possible to send a touched move event in the state |
+ // SINGLE_TAP_RELEASED or TOUCH_EXPLORE_RELEASED |
+ // because the events are not always generated in a sensical |
+ // order. If there is a NOTREACHED() for touch moved hit in |
aboxhall
2014/06/27 18:08:01
Will NOTREACHED() cause the test to crash in debug
evy
2014/06/27 21:00:03
Yup - I just fixed that problem, but forgot to cha
|
+ // InSingleTapOrTouchExploreReleased, that is fine here. |
+ |
+ // Keep track of what fingers have been pressed, to release |
+ // only those fingers at the end, so the check for being in |
+ // no fingers down can be accurate. |
+ if (next_dispatch->type() == ET_TOUCH_PRESSED) { |
+ fingers_pressed[next_dispatch->touch_id()] = true; |
+ } else if (next_dispatch->type() == ET_TOUCH_RELEASED) { |
+ fingers_pressed[next_dispatch->touch_id()] = false; |
+ } |
+ } |
+ ASSERT_EQ(queued_events.size(), 0u); |
+ |
+ // Release fingers recorded as pressed. |
+ for(int j = 0; j < int(fingers_pressed.size()); j++){ |
+ if (fingers_pressed[j] == true) { |
+ generator_->ReleaseTouchId(j); |
+ fingers_pressed[j] = false; |
+ } |
+ } |
+ AdvanceSimulatedTimePastTapDelay(); |
+ EXPECT_TRUE(IsInNoFingersDownState()); |
+ ClearCapturedEvents(); |
+ } |
+} |
+ |
} // namespace ui |