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/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 
     25 namespace {
     26 
     27 // A views::SliderListener that tracks simple event call history.
     28 class 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 
     79 TestSliderListener::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 
     87 TestSliderListener::~TestSliderListener() {
     88   last_drag_started_sender_ = NULL;
     89   last_drag_ended_sender_ = NULL;
     90 }
     91 
     92 void 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 
    100 void TestSliderListener::SliderValueChanged(views::Slider* sender,
    101                                             float value,
    102                                             float old_value,
    103                                             views::SliderChangeReason reason) {
    104   ++last_event_epoch_;
    105 }
    106 
    107 void TestSliderListener::SliderDragStarted(views::Slider* sender) {
    108   last_drag_started_sender_ = sender;
    109   last_drag_started_epoch_ = ++last_event_epoch_;
    110 }
    111 
    112 void TestSliderListener::SliderDragEnded(views::Slider* sender) {
    113   last_drag_ended_sender_ = sender;
    114   last_drag_ended_epoch_ = ++last_event_epoch_;
    115 }
    116 
    117 }  // namespace
    118 
    119 namespace views {
    120 
    121 // Base test fixture for Slider tests.
    122 class 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 
    176 SliderTest::SliderTest(Slider::Orientation orientation)
    177   : orientation_(orientation),
    178     slider_(NULL),
    179     default_locale_(""),
    180     max_x_(0),
    181     max_y_(0) {
    182 }
    183 
    184 SliderTest::~SliderTest() {
    185 }
    186 
    187 void 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 
    212 void SliderTest::TearDown() {
    213   if (widget_ && !widget_->IsClosed())
    214     widget_->Close();
    215 
    216   base::i18n::SetICUDefaultLocale(default_locale_);
    217 
    218   views::ViewsTestBase::TearDown();
    219 }
    220 
    221 void 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.
    228 class HorizontalSliderTest : public SliderTest {
    229  public:
    230   HorizontalSliderTest();
    231   virtual ~HorizontalSliderTest();
    232 
    233  private:
    234   DISALLOW_COPY_AND_ASSIGN(HorizontalSliderTest);
    235 };
    236 
    237 HorizontalSliderTest::HorizontalSliderTest()
    238   : SliderTest(Slider::HORIZONTAL) {
    239 }
    240 
    241 HorizontalSliderTest::~HorizontalSliderTest() {
    242 }
    243 
    244 // Test fixture for vertically oriented slider tests.
    245 class VerticalSliderTest : public SliderTest {
    246  public:
    247   VerticalSliderTest();
    248   virtual ~VerticalSliderTest();
    249 
    250  private:
    251   DISALLOW_COPY_AND_ASSIGN(VerticalSliderTest);
    252 };
    253 
    254 VerticalSliderTest::VerticalSliderTest()
    255   : SliderTest(Slider::VERTICAL) {
    256 }
    257 
    258 VerticalSliderTest::~VerticalSliderTest() {
    259 }
    260 
    261 TEST_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 
    269 TEST_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 
    277 TEST_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.
    288 TEST_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.
    306 TEST_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.
    336 TEST_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.
    348 TEST_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.
    367 TEST_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