WebKit/chromium/tests/PopupMenuTest.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2010 Google Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions are
       
     6  * met:
       
     7  *
       
     8  *     * Redistributions of source code must retain the above copyright
       
     9  * notice, this list of conditions and the following disclaimer.
       
    10  *     * Redistributions in binary form must reproduce the above
       
    11  * copyright notice, this list of conditions and the following disclaimer
       
    12  * in the documentation and/or other materials provided with the
       
    13  * distribution.
       
    14  *     * Neither the name of Google Inc. nor the names of its
       
    15  * contributors may be used to endorse or promote products derived from
       
    16  * this software without specific prior written permission.
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    29  */
       
    30 
       
    31 #include "config.h"
       
    32 
       
    33 #include <gtest/gtest.h>
       
    34 
       
    35 #include "Color.h"
       
    36 #include "KeyboardCodes.h"
       
    37 #include "PopupMenu.h"
       
    38 #include "PopupMenuClient.h"
       
    39 #include "PopupMenuChromium.h"
       
    40 #include "WebFrameClient.h"
       
    41 #include "WebFrameImpl.h"
       
    42 #include "WebInputEvent.h"
       
    43 #include "WebPopupMenuImpl.h"
       
    44 #include "WebScreenInfo.h"
       
    45 #include "WebViewClient.h"
       
    46 #include "WebViewImpl.h"
       
    47 
       
    48 using namespace WebCore;
       
    49 using namespace WebKit;
       
    50 
       
    51 namespace {
       
    52 
       
    53 class TestPopupMenuClient : public PopupMenuClient {
       
    54 public:
       
    55     // Item at index 0 is selected by default.
       
    56     TestPopupMenuClient() : m_selectIndex(0) { }
       
    57     virtual ~TestPopupMenuClient() {}
       
    58     virtual void valueChanged(unsigned listIndex, bool fireEvents = true)
       
    59     {
       
    60         m_selectIndex = listIndex;
       
    61     }
       
    62     virtual void selectionChanged(unsigned, bool) {}
       
    63     virtual void selectionCleared() {}
       
    64 
       
    65     virtual String itemText(unsigned listIndex) const
       
    66     {
       
    67         String str("Item ");
       
    68         str.append(String::number(listIndex));
       
    69         return str;
       
    70     }
       
    71     virtual String itemLabel(unsigned) const { return String(); }
       
    72     virtual String itemToolTip(unsigned listIndex) const { return itemText(listIndex); }
       
    73     virtual String itemAccessibilityText(unsigned listIndex) const { return itemText(listIndex); }
       
    74     virtual bool itemIsEnabled(unsigned listIndex) const { return true; }
       
    75     virtual PopupMenuStyle itemStyle(unsigned listIndex) const
       
    76     {
       
    77         Font font(FontPlatformData(12.0, false, false), false);
       
    78         return PopupMenuStyle(Color::black, Color::white, font, true, Length(), TextDirection());
       
    79     }
       
    80     virtual PopupMenuStyle menuStyle() const { return itemStyle(0); }
       
    81     virtual int clientInsetLeft() const { return 0; }
       
    82     virtual int clientInsetRight() const { return 0; }
       
    83     virtual int clientPaddingLeft() const { return 0; }
       
    84     virtual int clientPaddingRight() const { return 0; }
       
    85     virtual int listSize() const { return 10; }
       
    86     virtual int selectedIndex() const { return m_selectIndex; }
       
    87     virtual void popupDidHide() { }
       
    88     virtual bool itemIsSeparator(unsigned listIndex) const { return false; }
       
    89     virtual bool itemIsLabel(unsigned listIndex) const { return false; }
       
    90     virtual bool itemIsSelected(unsigned listIndex) const { return listIndex == m_selectIndex; }
       
    91     virtual bool shouldPopOver() const { return false; }
       
    92     virtual bool valueShouldChangeOnHotTrack() const { return false; }
       
    93     virtual void setTextFromItem(unsigned listIndex) { }
       
    94     
       
    95     virtual FontSelector* fontSelector() const { return 0; }
       
    96     virtual HostWindow* hostWindow() const { return 0; }
       
    97     
       
    98     virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize) { return 0; }
       
    99 
       
   100 private:
       
   101     unsigned m_selectIndex;
       
   102 };
       
   103 
       
   104 class TestWebWidgetClient : public WebWidgetClient {
       
   105 public:
       
   106     ~TestWebWidgetClient() { }
       
   107 };
       
   108 
       
   109 class TestWebPopupMenuImpl : public WebPopupMenuImpl {
       
   110 public:
       
   111     static PassRefPtr<TestWebPopupMenuImpl> create(WebWidgetClient* client)
       
   112     {
       
   113         return adoptRef(new TestWebPopupMenuImpl(client));
       
   114     }
       
   115 
       
   116     ~TestWebPopupMenuImpl() { }
       
   117 
       
   118 private:
       
   119     TestWebPopupMenuImpl(WebWidgetClient* client) : WebPopupMenuImpl(client) { }
       
   120 };
       
   121 
       
   122 class TestWebWidget : public WebWidget {
       
   123 public:
       
   124     virtual ~TestWebWidget() { }
       
   125     virtual void close() { }
       
   126     virtual WebSize size() { return WebSize(100, 100); }
       
   127     virtual void resize(const WebSize&) { }
       
   128     virtual void layout() { }
       
   129     virtual void paint(WebCanvas*, const WebRect&) { }
       
   130     virtual bool handleInputEvent(const WebInputEvent&) { return true; }
       
   131     virtual void mouseCaptureLost() { }
       
   132     virtual void setFocus(bool) { }
       
   133     virtual bool setComposition(
       
   134         const WebString& text,
       
   135         const WebVector<WebCompositionUnderline>& underlines,
       
   136         int selectionStart,
       
   137         int selectionEnd) { return true; }
       
   138     virtual bool confirmComposition() { return true; }
       
   139     virtual WebTextInputType textInputType() { return WebKit::WebTextInputTypeNone; }
       
   140     virtual WebRect caretOrSelectionBounds() { return WebRect(); }
       
   141     virtual void setTextDirection(WebTextDirection) { }
       
   142 };
       
   143 
       
   144 class TestWebViewClient : public WebViewClient {
       
   145 public:
       
   146     TestWebViewClient() : m_webPopupMenu(TestWebPopupMenuImpl::create(&m_webWidgetClient)) { }
       
   147     ~TestWebViewClient() { }
       
   148 
       
   149     virtual WebWidget* createPopupMenu(WebPopupType) { return m_webPopupMenu.get(); }
       
   150 
       
   151     // We need to override this so that the popup menu size is not 0
       
   152     // (the layout code checks to see if the popup fits on the screen).
       
   153     virtual WebScreenInfo screenInfo()
       
   154     { 
       
   155         WebScreenInfo screenInfo;
       
   156         screenInfo.availableRect.height = 2000;
       
   157         screenInfo.availableRect.width = 2000;
       
   158         return screenInfo;
       
   159     }
       
   160 
       
   161 private:
       
   162     TestWebWidgetClient m_webWidgetClient;
       
   163     RefPtr<TestWebPopupMenuImpl> m_webPopupMenu;
       
   164 };
       
   165 
       
   166 class TestWebFrameClient : public WebFrameClient {
       
   167 public:
       
   168     ~TestWebFrameClient() { }
       
   169 };
       
   170 
       
   171 class SelectPopupMenuTest : public testing::Test {
       
   172 public:
       
   173     SelectPopupMenuTest()
       
   174     {
       
   175     }
       
   176 
       
   177 protected:
       
   178     virtual void SetUp()
       
   179     {
       
   180         m_webView = static_cast<WebViewImpl*>(WebView::create(&m_webviewClient, 0));
       
   181         m_webView->initializeMainFrame(&m_webFrameClient);
       
   182         m_popupMenu = PopupMenu::create(&m_popupMenuClient);
       
   183     }
       
   184 
       
   185     virtual void TearDown()
       
   186     {
       
   187         m_popupMenu = 0;
       
   188         m_webView->close();
       
   189     }
       
   190 
       
   191     // Returns true if there currently is a select popup in the WebView.
       
   192     bool popupOpen() const { return m_webView->selectPopup(); }
       
   193 
       
   194     int selectedIndex() const { return m_popupMenuClient.selectedIndex(); }
       
   195 
       
   196     void showPopup()
       
   197     {
       
   198         m_popupMenu->show(IntRect(0, 0, 100, 100),
       
   199             static_cast<WebFrameImpl*>(m_webView->mainFrame())->frameView(), 0);
       
   200         ASSERT_TRUE(popupOpen());
       
   201         EXPECT_TRUE(m_webView->selectPopup()->popupType() == PopupContainer::Select);
       
   202     }
       
   203 
       
   204     void hidePopup()
       
   205     {
       
   206         m_popupMenu->hide();
       
   207         EXPECT_FALSE(popupOpen());
       
   208     }
       
   209 
       
   210     void simulateKeyDownEvent(int keyCode)
       
   211     {
       
   212         simulateKeyEvent(WebInputEvent::RawKeyDown, keyCode);
       
   213     }
       
   214 
       
   215     void simulateKeyUpEvent(int keyCode)
       
   216     {
       
   217         simulateKeyEvent(WebInputEvent::KeyUp, keyCode);
       
   218     }
       
   219 
       
   220     // Simulates a key event on the WebView.
       
   221     // The WebView forwards the event to the select popup if one is open.
       
   222     void simulateKeyEvent(WebInputEvent::Type eventType, int keyCode)
       
   223     {
       
   224         WebKeyboardEvent keyEvent;
       
   225         keyEvent.windowsKeyCode = keyCode;
       
   226         keyEvent.type = eventType;
       
   227         m_webView->handleInputEvent(keyEvent);
       
   228     }
       
   229 
       
   230     // Simulates a mouse event on the select popup.
       
   231     void simulateLeftMouseDownEvent(const IntPoint& point)
       
   232     {
       
   233         PlatformMouseEvent mouseEvent(point, point, LeftButton, MouseEventPressed,
       
   234                                       1, false, false, false, false, 0);
       
   235         m_webView->selectPopup()->handleMouseDownEvent(mouseEvent);
       
   236     }
       
   237     void simulateLeftMouseUpEvent(const IntPoint& point)
       
   238     {
       
   239         PlatformMouseEvent mouseEvent(point, point, LeftButton, MouseEventReleased,
       
   240                                       1, false, false, false, false, 0);
       
   241         m_webView->selectPopup()->handleMouseReleaseEvent(mouseEvent);
       
   242     }
       
   243 
       
   244 protected:
       
   245     TestWebViewClient m_webviewClient;
       
   246     WebViewImpl* m_webView;
       
   247     TestWebFrameClient m_webFrameClient;
       
   248     TestPopupMenuClient m_popupMenuClient;
       
   249     RefPtr<PopupMenu> m_popupMenu;
       
   250 };
       
   251 
       
   252 // Tests that show/hide and repeats.  Select popups are reused in web pages when
       
   253 // they are reopened, that what this is testing.
       
   254 TEST_F(SelectPopupMenuTest, ShowThenHide)
       
   255 {
       
   256     for (int i = 0; i < 3; i++) {
       
   257         showPopup();
       
   258         hidePopup();
       
   259     }
       
   260 }
       
   261 
       
   262 // Tests that showing a select popup and deleting it does not cause problem.
       
   263 // This happens in real-life if a page navigates while a select popup is showing.
       
   264 TEST_F(SelectPopupMenuTest, ShowThenDelete)
       
   265 {
       
   266     showPopup();
       
   267     // Nothing else to do, TearDown() deletes the popup.
       
   268 }
       
   269 
       
   270 // Tests that losing focus closes the select popup.
       
   271 TEST_F(SelectPopupMenuTest, ShowThenLoseFocus)
       
   272 {
       
   273     showPopup();
       
   274     // Simulate losing focus.
       
   275     m_webView->setFocus(false);
       
   276 
       
   277     // Popup should have closed.
       
   278     EXPECT_FALSE(popupOpen());
       
   279 }
       
   280 
       
   281 // Tests that pressing ESC closes the popup.
       
   282 TEST_F(SelectPopupMenuTest, ShowThenPressESC)
       
   283 {
       
   284     showPopup();
       
   285     simulateKeyDownEvent(VKEY_ESCAPE);
       
   286     // Popup should have closed.
       
   287     EXPECT_FALSE(popupOpen());
       
   288 }
       
   289 
       
   290 // Tests selecting an item with the arrows and enter/esc/tab.
       
   291 TEST_F(SelectPopupMenuTest, SelectWithKeys)
       
   292 {
       
   293     showPopup();
       
   294     // Simulate selecting the 2nd item by pressing Down, Down, enter.
       
   295     simulateKeyDownEvent(VKEY_DOWN);
       
   296     simulateKeyDownEvent(VKEY_DOWN);
       
   297     simulateKeyDownEvent(VKEY_RETURN);
       
   298 
       
   299     // Popup should have closed.
       
   300     EXPECT_TRUE(!popupOpen());
       
   301     EXPECT_EQ(2, selectedIndex());
       
   302 
       
   303     // It should work as well with ESC.
       
   304     showPopup();
       
   305     simulateKeyDownEvent(VKEY_DOWN);
       
   306     simulateKeyDownEvent(VKEY_ESCAPE);
       
   307     EXPECT_FALSE(popupOpen());
       
   308     EXPECT_EQ(3, selectedIndex());
       
   309 
       
   310     // It should work as well with TAB.
       
   311     showPopup();
       
   312     simulateKeyDownEvent(VKEY_DOWN);
       
   313     simulateKeyDownEvent(VKEY_TAB);
       
   314     EXPECT_FALSE(popupOpen());
       
   315     EXPECT_EQ(4, selectedIndex());
       
   316 }
       
   317 
       
   318 // Tests that selecting an item with the mouse does select the item and close
       
   319 // the popup.
       
   320 TEST_F(SelectPopupMenuTest, ClickItem)
       
   321 {
       
   322     showPopup();
       
   323 
       
   324     // Y of 18 to be on the item at index 1 (12 font plus border and more to be safe).
       
   325     IntPoint row1Point(2, 18);
       
   326     // Simulate a click down/up on the first item.
       
   327     simulateLeftMouseDownEvent(row1Point);
       
   328     simulateLeftMouseUpEvent(row1Point);
       
   329 
       
   330     // Popup should have closed and the item at index 1 selected.
       
   331     EXPECT_FALSE(popupOpen());
       
   332     EXPECT_EQ(1, selectedIndex());
       
   333 }
       
   334 
       
   335 // Tests that moving the mouse over an item and then clicking outside the select popup
       
   336 // leaves the seleted item unchanged.
       
   337 TEST_F(SelectPopupMenuTest, MouseOverItemClickOutside)
       
   338 {
       
   339     showPopup();
       
   340 
       
   341     // Y of 18 to be on the item at index 1 (12 font plus border and more to be safe).
       
   342     IntPoint row1Point(2, 18);
       
   343     // Simulate the mouse moving over the first item.
       
   344     PlatformMouseEvent mouseEvent(row1Point, row1Point, NoButton, MouseEventMoved,
       
   345                                   1, false, false, false, false, 0);
       
   346     m_webView->selectPopup()->handleMouseMoveEvent(mouseEvent);
       
   347 
       
   348     // Click outside the popup.
       
   349     simulateLeftMouseDownEvent(IntPoint(1000, 1000));
       
   350 
       
   351     // Popup should have closed and item 0 should still be selected.
       
   352     EXPECT_FALSE(popupOpen());
       
   353     EXPECT_EQ(0, selectedIndex());
       
   354 }
       
   355 
       
   356 // Tests that selecting an item with the keyboard and then clicking outside the select
       
   357 // popup does select that item.
       
   358 TEST_F(SelectPopupMenuTest, SelectItemWithKeyboardItemClickOutside)
       
   359 {
       
   360     showPopup();
       
   361 
       
   362     // Simulate selecting the 2nd item by pressing Down, Down.
       
   363     simulateKeyDownEvent(VKEY_DOWN);
       
   364     simulateKeyDownEvent(VKEY_DOWN);
       
   365 
       
   366     // Click outside the popup.
       
   367     simulateLeftMouseDownEvent(IntPoint(1000, 1000));
       
   368 
       
   369     // Popup should have closed and the item should have been selected.
       
   370     EXPECT_FALSE(popupOpen());
       
   371     EXPECT_EQ(2, selectedIndex());
       
   372 }
       
   373 
       
   374 } // namespace