text: // Copyright (c) 2012 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/views/controls/scrollbar/native_scroll_bar.h"
  #include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
  #include "ui/views/controls/scrollbar/scroll_bar.h"
  #include "ui/views/test/views_test_base.h"
  #include "ui/views/widget/widget.h"
  
  namespace {
  
  // The Scrollbar controller. This is the widget that should do the real
  // scrolling of contents.
  class TestScrollBarController : public views::ScrollBarController {
   public:
    virtual ~TestScrollBarController() {}
  
    void ScrollToPosition(views::ScrollBar* source, int position) override {
      last_source = source;
      last_position = position;
    }
  
    int GetScrollIncrement(views::ScrollBar* source,
                           bool is_page,
                           bool is_positive) override {
      last_source = source;
      last_is_page = is_page;
      last_is_positive = is_positive;
  
      if (is_page)
        return 20;
      return 10;
    }
  
    // We save the last values in order to assert the corectness of the scroll
    // operation.
    views::ScrollBar* last_source;
    bool last_is_positive;
    bool last_is_page;
    int last_position;
  };
  
  }  // namespace
  
  namespace views {
  
  class NativeScrollBarTest : public ViewsTestBase {
   public:
    NativeScrollBarTest() : widget_(NULL), scrollbar_(NULL) {}
  
    void SetUp() override {
      ViewsTestBase::SetUp();
      controller_.reset(new TestScrollBarController());
  
      ASSERT_FALSE(scrollbar_);
      native_scrollbar_ = new NativeScrollBar(true);
      native_scrollbar_->SetBounds(0, 0, 100, 100);
      native_scrollbar_->set_controller(controller_.get());
  
      widget_ = new Widget;
      Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
      params.bounds = gfx::Rect(0, 0, 100, 100);
      widget_->Init(params);
      View* container = new View();
      widget_->SetContentsView(container);
      container->AddChildView(native_scrollbar_);
  
      scrollbar_ =
          static_cast<NativeScrollBarViews*>(native_scrollbar_->native_wrapper_);
      scrollbar_->SetBounds(0, 0, 100, 100);
      scrollbar_->Update(100, 200, 0);
  
      track_size_ = scrollbar_->GetTrackBounds().width();
    }
  
    void TearDown() override {
      widget_->Close();
      ViewsTestBase::TearDown();
    }
  
   protected:
    Widget* widget_;
  
    // This is the native scrollbar the Views one wraps around.
    NativeScrollBar* native_scrollbar_;
  
    // This is the Views scrollbar.
    BaseScrollBar* scrollbar_;
  
    // Keep track of the size of the track. This is how we can tell when we
    // scroll to the middle.
    int track_size_;
  
    scoped_ptr<TestScrollBarController> controller_;
  };
  
  // TODO(dnicoara) Can't run the test on Windows since the scrollbar |Part|
  // isn't handled in NativeTheme.
  #if defined(OS_WIN)
  #define MAYBE_Scrolling DISABLED_Scrolling
  #define MAYBE_ScrollBarFitsToBottom DISABLED_ScrollBarFitsToBottom
  #else
  #define MAYBE_Scrolling Scrolling
  #define MAYBE_ScrollBarFitsToBottom ScrollBarFitsToBottom
  #endif
  
  TEST_F(NativeScrollBarTest, MAYBE_Scrolling) {
    EXPECT_EQ(scrollbar_->GetPosition(), 0);
    EXPECT_EQ(scrollbar_->GetMaxPosition(), 100);
    EXPECT_EQ(scrollbar_->GetMinPosition(), 0);
  
    // Scroll to middle.
    scrollbar_->ScrollToThumbPosition(track_size_ / 4, false);
    EXPECT_EQ(controller_->last_position, 50);
    EXPECT_EQ(controller_->last_source, native_scrollbar_);
  
    // Scroll to the end.
    scrollbar_->ScrollToThumbPosition(track_size_ / 2, false);
    EXPECT_EQ(controller_->last_position, 100);
  
    // Overscroll. Last position should be the maximum position.
    scrollbar_->ScrollToThumbPosition(track_size_, false);
    EXPECT_EQ(controller_->last_position, 100);
  
    // Underscroll. Last position should be the minimum position.
    scrollbar_->ScrollToThumbPosition(-10, false);
    EXPECT_EQ(controller_->last_position, 0);
  
    // Test the different fixed scrolling amounts. Generally used by buttons,
    // or click on track.
    scrollbar_->ScrollToThumbPosition(0, false);
    scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_LINE);
    EXPECT_EQ(controller_->last_position, 10);
  
    scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_PREV_LINE);
    EXPECT_EQ(controller_->last_position, 0);
  
    scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_PAGE);
    EXPECT_EQ(controller_->last_position, 20);
  
    scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_PREV_PAGE);
    EXPECT_EQ(controller_->last_position, 0);
  }
  
  TEST_F(NativeScrollBarTest, MAYBE_ScrollBarFitsToBottom) {
    scrollbar_->Update(100, 199, 0);
    EXPECT_EQ(0, scrollbar_->GetPosition());
    EXPECT_EQ(99, scrollbar_->GetMaxPosition());
    EXPECT_EQ(0, scrollbar_->GetMinPosition());
  
    scrollbar_->Update(100, 199, 99);
    EXPECT_EQ(
        scrollbar_->GetTrackBounds().width() - scrollbar_->GetThumbSizeForTest(),
        scrollbar_->GetPosition());
  }
  
  TEST_F(NativeScrollBarTest, ScrollToEndAfterShrinkAndExpand) {
    // Scroll to the end of the content.
    scrollbar_->Update(100, 101, 0);
    EXPECT_TRUE(scrollbar_->ScrollByContentsOffset(-1));
    // Shrink and then re-exapnd the content.
    scrollbar_->Update(100, 100, 0);
    scrollbar_->Update(100, 101, 0);
    // Ensure the scrollbar allows scrolling to the end.
    EXPECT_TRUE(scrollbar_->ScrollByContentsOffset(-1));
  }
  
  }  // namespace views
  