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