1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ui/views/controls/slider.h" 6 7#include <string> 8 9#include "base/memory/scoped_ptr.h" 10#include "base/strings/string_util.h" 11#include "base/strings/utf_string_conversions.h" 12#include "base/time/time.h" 13#include "testing/gtest/include/gtest/gtest.h" 14#include "ui/aura/test/event_generator.h" 15#include "ui/aura/window.h" 16#include "ui/base/l10n/l10n_util.h" 17#include "ui/events/event.h" 18#include "ui/events/gesture_event_details.h" 19#include "ui/views/test/slider_test_api.h" 20#include "ui/views/test/views_test_base.h" 21#include "ui/views/view.h" 22#include "ui/views/widget/widget.h" 23#include "ui/views/widget/widget_delegate.h" 24 25namespace { 26 27// A views::SliderListener that tracks simple event call history. 28class TestSliderListener : public views::SliderListener { 29 public: 30 TestSliderListener(); 31 virtual ~TestSliderListener(); 32 33 int last_event_epoch() { 34 return last_event_epoch_; 35 } 36 37 int last_drag_started_epoch() { 38 return last_drag_started_epoch_; 39 } 40 41 int last_drag_ended_epoch() { 42 return last_drag_ended_epoch_; 43 } 44 45 views::Slider* last_drag_started_sender() { 46 return last_drag_started_sender_; 47 } 48 49 views::Slider* last_drag_ended_sender() { 50 return last_drag_ended_sender_; 51 } 52 53 // Resets the state of this as if it were newly created. 54 virtual void ResetCallHistory(); 55 56 // views::SliderListener: 57 virtual void SliderValueChanged(views::Slider* sender, 58 float value, 59 float old_value, 60 views::SliderChangeReason reason) OVERRIDE; 61 virtual void SliderDragStarted(views::Slider* sender) OVERRIDE; 62 virtual void SliderDragEnded(views::Slider* sender) OVERRIDE; 63 64 private: 65 // The epoch of the last event. 66 int last_event_epoch_; 67 // The epoch of the last time SliderDragStarted was called. 68 int last_drag_started_epoch_; 69 // The epoch of the last time SliderDragEnded was called. 70 int last_drag_ended_epoch_; 71 // The sender from the last SliderDragStarted call. 72 views::Slider* last_drag_started_sender_; 73 // The sender from the last SliderDragEnded call. 74 views::Slider* last_drag_ended_sender_; 75 76 DISALLOW_COPY_AND_ASSIGN(TestSliderListener); 77}; 78 79TestSliderListener::TestSliderListener() 80 : last_event_epoch_(0), 81 last_drag_started_epoch_(-1), 82 last_drag_ended_epoch_(-1), 83 last_drag_started_sender_(NULL), 84 last_drag_ended_sender_(NULL) { 85} 86 87TestSliderListener::~TestSliderListener() { 88 last_drag_started_sender_ = NULL; 89 last_drag_ended_sender_ = NULL; 90} 91 92void TestSliderListener::ResetCallHistory() { 93 last_event_epoch_ = 0; 94 last_drag_started_epoch_ = -1; 95 last_drag_ended_epoch_ = -1; 96 last_drag_started_sender_ = NULL; 97 last_drag_ended_sender_ = NULL; 98} 99 100void TestSliderListener::SliderValueChanged(views::Slider* sender, 101 float value, 102 float old_value, 103 views::SliderChangeReason reason) { 104 ++last_event_epoch_; 105} 106 107void TestSliderListener::SliderDragStarted(views::Slider* sender) { 108 last_drag_started_sender_ = sender; 109 last_drag_started_epoch_ = ++last_event_epoch_; 110} 111 112void TestSliderListener::SliderDragEnded(views::Slider* sender) { 113 last_drag_ended_sender_ = sender; 114 last_drag_ended_epoch_ = ++last_event_epoch_; 115} 116 117} // namespace 118 119namespace views { 120 121// Base test fixture for Slider tests. 122class SliderTest : public views::ViewsTestBase { 123 public: 124 explicit SliderTest(Slider::Orientation orientation); 125 virtual ~SliderTest(); 126 127 protected: 128 Slider* slider() { 129 return slider_; 130 } 131 132 TestSliderListener& slider_listener() { 133 return slider_listener_; 134 } 135 136 int max_x() { 137 return max_x_; 138 } 139 140 int max_y() { 141 return max_y_; 142 } 143 144 virtual void ClickAt(int x, int y); 145 146 // testing::Test: 147 virtual void SetUp() OVERRIDE; 148 virtual void TearDown() OVERRIDE; 149 150 aura::test::EventGenerator* event_generator() { 151 return event_generator_.get(); 152 } 153 154 private: 155 // The Slider's orientation 156 Slider::Orientation orientation_; 157 // The Slider to be tested. 158 Slider* slider_; 159 // A simple SliderListener test double. 160 TestSliderListener slider_listener_; 161 // Stores the default locale at test setup so it can be restored 162 // during test teardown. 163 std::string default_locale_; 164 // The maximum x value within the bounds of the slider. 165 int max_x_; 166 // The maximum y value within the bounds of the slider. 167 int max_y_; 168 // The widget container for the slider being tested. 169 views::Widget* widget_; 170 // An event generator. 171 scoped_ptr<aura::test::EventGenerator> event_generator_; 172 173 DISALLOW_COPY_AND_ASSIGN(SliderTest); 174}; 175 176SliderTest::SliderTest(Slider::Orientation orientation) 177 : orientation_(orientation), 178 slider_(NULL), 179 default_locale_(""), 180 max_x_(0), 181 max_y_(0) { 182} 183 184SliderTest::~SliderTest() { 185} 186 187void SliderTest::SetUp() { 188 views::ViewsTestBase::SetUp(); 189 190 slider_ = new Slider(NULL, orientation_); 191 View* view = slider_; 192 gfx::Size size = view->GetPreferredSize(); 193 view->SetSize(size); 194 max_x_ = size.width() - 1; 195 max_y_ = size.height() - 1; 196 default_locale_ = l10n_util::GetApplicationLocale(""); 197 198 views::Widget::InitParams init_params(CreateParams( 199 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS)); 200 init_params.bounds = gfx::Rect(size); 201 202 widget_ = new views::Widget(); 203 widget_->Init(init_params); 204 widget_->SetContentsView(slider_); 205 widget_->Show(); 206 207 aura::Window* native_window = widget_->GetNativeWindow(); 208 event_generator_.reset(new aura::test::EventGenerator( 209 native_window->GetRootWindow())); 210} 211 212void SliderTest::TearDown() { 213 if (widget_ && !widget_->IsClosed()) 214 widget_->Close(); 215 216 base::i18n::SetICUDefaultLocale(default_locale_); 217 218 views::ViewsTestBase::TearDown(); 219} 220 221void SliderTest::ClickAt(int x, int y) { 222 gfx::Point point(x, y); 223 event_generator_->MoveMouseTo(point); 224 event_generator_->ClickLeftButton(); 225} 226 227// Test fixture for horizontally oriented slider tests. 228class HorizontalSliderTest : public SliderTest { 229 public: 230 HorizontalSliderTest(); 231 virtual ~HorizontalSliderTest(); 232 233 private: 234 DISALLOW_COPY_AND_ASSIGN(HorizontalSliderTest); 235}; 236 237HorizontalSliderTest::HorizontalSliderTest() 238 : SliderTest(Slider::HORIZONTAL) { 239} 240 241HorizontalSliderTest::~HorizontalSliderTest() { 242} 243 244// Test fixture for vertically oriented slider tests. 245class VerticalSliderTest : public SliderTest { 246 public: 247 VerticalSliderTest(); 248 virtual ~VerticalSliderTest(); 249 250 private: 251 DISALLOW_COPY_AND_ASSIGN(VerticalSliderTest); 252}; 253 254VerticalSliderTest::VerticalSliderTest() 255 : SliderTest(Slider::VERTICAL) { 256} 257 258VerticalSliderTest::~VerticalSliderTest() { 259} 260 261TEST_F(HorizontalSliderTest, UpdateFromClickHorizontal) { 262 ClickAt(0, 0); 263 EXPECT_EQ(0.0f, slider()->value()); 264 265 ClickAt(max_x(), 0); 266 EXPECT_EQ(1.0f, slider()->value()); 267} 268 269TEST_F(VerticalSliderTest, UpdateFromClickVertical) { 270 ClickAt(0, 0); 271 EXPECT_EQ(1.0f, slider()->value()); 272 273 ClickAt(0, max_y()); 274 EXPECT_EQ(0.0f, slider()->value()); 275} 276 277TEST_F(HorizontalSliderTest, UpdateFromClickRTLHorizontal) { 278 base::i18n::SetICUDefaultLocale("he"); 279 280 ClickAt(0, 0); 281 EXPECT_EQ(1.0f, slider()->value()); 282 283 ClickAt(max_x(), 0); 284 EXPECT_EQ(0.0f, slider()->value()); 285} 286 287// Test the slider location after a tap gesture. 288TEST_F(HorizontalSliderTest, SliderValueForTapGesture) { 289 // Tap below the minimum. 290 slider()->SetValue(0.5); 291 event_generator()->GestureTapAt(gfx::Point(0, 0)); 292 EXPECT_FLOAT_EQ(0, slider()->value()); 293 294 // Tap above the maximum. 295 slider()->SetValue(0.5); 296 event_generator()->GestureTapAt(gfx::Point(max_x(), max_y())); 297 EXPECT_FLOAT_EQ(1, slider()->value()); 298 299 // Tap somwhere in the middle. 300 slider()->SetValue(0.5); 301 event_generator()->GestureTapAt(gfx::Point(0.75 * max_x(), 0.75 * max_y())); 302 EXPECT_NEAR(0.75, slider()->value(), 0.03); 303} 304 305// Test the slider location after a scroll gesture. 306TEST_F(HorizontalSliderTest, SliderValueForScrollGesture) { 307 // Scroll below the minimum. 308 slider()->SetValue(0.5); 309 event_generator()->GestureScrollSequence( 310 gfx::Point(0.5 * max_x(), 0.5 * max_y()), 311 gfx::Point(0, 0), 312 base::TimeDelta::FromMilliseconds(10), 313 5 /* steps */); 314 EXPECT_EQ(0, slider()->value()); 315 316 // Scroll above the maximum. 317 slider()->SetValue(0.5); 318 event_generator()->GestureScrollSequence( 319 gfx::Point(0.5 * max_x(), 0.5 * max_y()), 320 gfx::Point(max_x(), max_y()), 321 base::TimeDelta::FromMilliseconds(10), 322 5 /* steps */); 323 EXPECT_EQ(1, slider()->value()); 324 325 // Scroll somewhere in the middle. 326 slider()->SetValue(0.25); 327 event_generator()->GestureScrollSequence( 328 gfx::Point(0.25 * max_x(), 0.25 * max_y()), 329 gfx::Point(0.75 * max_x(), 0.75 * max_y()), 330 base::TimeDelta::FromMilliseconds(10), 331 5 /* steps */); 332 EXPECT_NEAR(0.75, slider()->value(), 0.03); 333} 334 335// Verifies the correct SliderListener events are raised for a tap gesture. 336TEST_F(HorizontalSliderTest, SliderListenerEventsForTapGesture) { 337 test::SliderTestApi slider_test_api(slider()); 338 slider_test_api.SetListener(&slider_listener()); 339 340 event_generator()->GestureTapAt(gfx::Point(0, 0)); 341 EXPECT_EQ(1, slider_listener().last_drag_started_epoch()); 342 EXPECT_EQ(2, slider_listener().last_drag_ended_epoch()); 343 EXPECT_EQ(slider(), slider_listener().last_drag_started_sender()); 344 EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender()); 345} 346 347// Verifies the correct SliderListener events are raised for a scroll gesture. 348TEST_F(HorizontalSliderTest, SliderListenerEventsForScrollGesture) { 349 test::SliderTestApi slider_test_api(slider()); 350 slider_test_api.SetListener(&slider_listener()); 351 352 event_generator()->GestureScrollSequence( 353 gfx::Point(0.25 * max_x(), 0.25 * max_y()), 354 gfx::Point(0.75 * max_x(), 0.75 * max_y()), 355 base::TimeDelta::FromMilliseconds(0), 356 5 /* steps */); 357 358 EXPECT_EQ(1, slider_listener().last_drag_started_epoch()); 359 EXPECT_GT(slider_listener().last_drag_ended_epoch(), 360 slider_listener().last_drag_started_epoch()); 361 EXPECT_EQ(slider(), slider_listener().last_drag_started_sender()); 362 EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender()); 363} 364 365// Verifies the correct SliderListener events are raised for a multi 366// finger scroll gesture. 367TEST_F(HorizontalSliderTest, SliderListenerEventsForMultiFingerScrollGesture) { 368 test::SliderTestApi slider_test_api(slider()); 369 slider_test_api.SetListener(&slider_listener()); 370 371 gfx::Point points[] = {gfx::Point(0, 0.1 * max_y()), 372 gfx::Point(0, 0.2 * max_y())}; 373 event_generator()->GestureMultiFingerScroll(2 /* count */, points, 374 0 /* event_separation_time_ms */, 5 /* steps */, 375 2 /* move_x */, 0 /* move_y */); 376 377 EXPECT_EQ(1, slider_listener().last_drag_started_epoch()); 378 EXPECT_GT(slider_listener().last_drag_ended_epoch(), 379 slider_listener().last_drag_started_epoch()); 380 EXPECT_EQ(slider(), slider_listener().last_drag_started_sender()); 381 EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender()); 382} 383 384} // namespace views 385