Home | History | Annotate | Download | only in speech
      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 "base/bind.h"
      6 #include "base/run_loop.h"
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/speech/speech_recognition_bubble_controller.h"
      9 #include "chrome/browser/ui/browser.h"
     10 #include "chrome/browser/ui/browser_tabstrip.h"
     11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     12 #include "chrome/test/base/browser_with_test_window_test.h"
     13 #include "chrome/test/base/testing_profile.h"
     14 #include "content/public/test/test_browser_thread.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #include "ui/gfx/rect.h"
     17 
     18 using content::BrowserThread;
     19 using content::WebContents;
     20 
     21 namespace speech {
     22 
     23 // A mock bubble class which fakes a focus change or recognition cancel by the
     24 // user and closing of the info bubble.
     25 class MockSpeechRecognitionBubble : public SpeechRecognitionBubbleBase {
     26  public:
     27   enum BubbleType {
     28     BUBBLE_TEST_FOCUS_CHANGED,
     29     BUBBLE_TEST_CLICK_CANCEL,
     30     BUBBLE_TEST_CLICK_TRY_AGAIN,
     31   };
     32 
     33   MockSpeechRecognitionBubble(WebContents* web_contents,
     34                         Delegate* delegate,
     35                         const gfx::Rect&)
     36       : SpeechRecognitionBubbleBase(web_contents) {
     37     VLOG(1) << "MockSpeechRecognitionBubble created";
     38     base::MessageLoop::current()->PostTask(
     39         FROM_HERE, base::Bind(&InvokeDelegate, delegate));
     40   }
     41 
     42   static void InvokeDelegate(Delegate* delegate) {
     43     VLOG(1) << "MockSpeechRecognitionBubble invoking delegate for type "
     44             << type_;
     45     switch (type_) {
     46       case BUBBLE_TEST_FOCUS_CHANGED:
     47         delegate->InfoBubbleFocusChanged();
     48         break;
     49       case BUBBLE_TEST_CLICK_CANCEL:
     50         delegate->InfoBubbleButtonClicked(
     51             SpeechRecognitionBubble::BUTTON_CANCEL);
     52         break;
     53       case BUBBLE_TEST_CLICK_TRY_AGAIN:
     54         delegate->InfoBubbleButtonClicked(
     55             SpeechRecognitionBubble::BUTTON_TRY_AGAIN);
     56         break;
     57     }
     58   }
     59 
     60   static void set_type(BubbleType type) {
     61     type_ = type;
     62   }
     63   static BubbleType type() {
     64     return type_;
     65   }
     66 
     67   virtual void Show() OVERRIDE {}
     68   virtual void Hide() OVERRIDE {}
     69   virtual void UpdateLayout() OVERRIDE {}
     70   virtual void UpdateImage() OVERRIDE {}
     71 
     72  private:
     73   static BubbleType type_;
     74 };
     75 
     76 // The test fixture.
     77 class SpeechRecognitionBubbleControllerTest
     78     : public SpeechRecognitionBubbleControllerDelegate,
     79       public BrowserWithTestWindowTest {
     80  public:
     81   SpeechRecognitionBubbleControllerTest()
     82       : BrowserWithTestWindowTest(),
     83         cancel_clicked_(false),
     84         try_again_clicked_(false),
     85         focus_changed_(false),
     86         controller_(new SpeechRecognitionBubbleController(this)) {
     87     EXPECT_EQ(NULL, test_fixture_);
     88     test_fixture_ = this;
     89   }
     90 
     91   virtual ~SpeechRecognitionBubbleControllerTest() {
     92     test_fixture_ = NULL;
     93   }
     94 
     95   // SpeechRecognitionBubbleControllerDelegate methods.
     96   virtual void InfoBubbleButtonClicked(
     97       int session_id,
     98       SpeechRecognitionBubble::Button button) OVERRIDE {
     99     VLOG(1) << "Received InfoBubbleButtonClicked for button " << button;
    100     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    101     if (button == SpeechRecognitionBubble::BUTTON_CANCEL) {
    102       cancel_clicked_ = true;
    103     } else if (button == SpeechRecognitionBubble::BUTTON_TRY_AGAIN) {
    104       try_again_clicked_ = true;
    105     }
    106   }
    107 
    108   virtual void InfoBubbleFocusChanged(int session_id) OVERRIDE {
    109     VLOG(1) << "Received InfoBubbleFocusChanged";
    110     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    111     focus_changed_ = true;
    112   }
    113 
    114   // testing::Test methods.
    115   virtual void SetUp() {
    116     BrowserWithTestWindowTest::SetUp();
    117     SpeechRecognitionBubble::set_factory(
    118         &SpeechRecognitionBubbleControllerTest::CreateBubble);
    119   }
    120 
    121   virtual void TearDown() {
    122     SpeechRecognitionBubble::set_factory(NULL);
    123     BrowserWithTestWindowTest::TearDown();
    124   }
    125 
    126   static void ActivateBubble() {
    127     if (MockSpeechRecognitionBubble::type() !=
    128         MockSpeechRecognitionBubble::BUBBLE_TEST_FOCUS_CHANGED) {
    129       test_fixture_->controller_->SetBubbleMessage(ASCIIToUTF16("Test"));
    130     }
    131   }
    132 
    133   static SpeechRecognitionBubble* CreateBubble(
    134       WebContents* web_contents,
    135       SpeechRecognitionBubble::Delegate* delegate,
    136       const gfx::Rect& element_rect) {
    137     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
    138     // Set up to activate the bubble soon after it gets created, since we test
    139     // events sent by the bubble and those are handled only when the bubble is
    140     // active.
    141     base::MessageLoop::current()->PostTask(FROM_HERE,
    142                                            base::Bind(&ActivateBubble));
    143 
    144     // The |web_contents| parameter would be NULL since the dummy session id
    145     // passed to CreateBubble would not have matched any active tab. So get a
    146     // real WebContents pointer from the test fixture and pass that, because
    147     // the bubble controller registers for tab close notifications which need
    148     // a valid WebContents.
    149     web_contents =
    150         test_fixture_->browser()->tab_strip_model()->GetActiveWebContents();
    151     return new MockSpeechRecognitionBubble(web_contents, delegate,
    152                                            element_rect);
    153   }
    154 
    155  protected:
    156   bool cancel_clicked_;
    157   bool try_again_clicked_;
    158   bool focus_changed_;
    159   scoped_refptr<SpeechRecognitionBubbleController> controller_;
    160 
    161   static const int kBubbleSessionId;
    162   static SpeechRecognitionBubbleControllerTest* test_fixture_;
    163 };
    164 
    165 SpeechRecognitionBubbleControllerTest*
    166 SpeechRecognitionBubbleControllerTest::test_fixture_ = NULL;
    167 
    168 const int SpeechRecognitionBubbleControllerTest::kBubbleSessionId = 1;
    169 
    170 MockSpeechRecognitionBubble::BubbleType MockSpeechRecognitionBubble::type_ =
    171     MockSpeechRecognitionBubble::BUBBLE_TEST_FOCUS_CHANGED;
    172 
    173 // Test that the speech bubble UI gets created in the UI thread and that the
    174 // focus changed callback comes back in the IO thread.
    175 TEST_F(SpeechRecognitionBubbleControllerTest, TestFocusChanged) {
    176   MockSpeechRecognitionBubble::set_type(
    177       MockSpeechRecognitionBubble::BUBBLE_TEST_FOCUS_CHANGED);
    178 
    179   controller_->CreateBubble(kBubbleSessionId, 1, 1, gfx::Rect(1, 1));
    180   base::RunLoop().RunUntilIdle();
    181   EXPECT_TRUE(focus_changed_);
    182   EXPECT_FALSE(cancel_clicked_);
    183   EXPECT_FALSE(try_again_clicked_);
    184   controller_->CloseBubble();
    185 }
    186 
    187 // Test that the speech bubble UI gets created in the UI thread and that the
    188 // recognition cancelled callback comes back in the IO thread.
    189 TEST_F(SpeechRecognitionBubbleControllerTest, TestRecognitionCancelled) {
    190   MockSpeechRecognitionBubble::set_type(
    191       MockSpeechRecognitionBubble::BUBBLE_TEST_CLICK_CANCEL);
    192 
    193   controller_->CreateBubble(kBubbleSessionId, 1, 1, gfx::Rect(1, 1));
    194   base::RunLoop().RunUntilIdle();
    195   EXPECT_TRUE(cancel_clicked_);
    196   EXPECT_FALSE(try_again_clicked_);
    197   EXPECT_FALSE(focus_changed_);
    198   controller_->CloseBubble();
    199 }
    200 
    201 // Test that the speech bubble UI gets created in the UI thread and that the
    202 // try-again button click event comes back in the IO thread.
    203 TEST_F(SpeechRecognitionBubbleControllerTest, TestTryAgainClicked) {
    204   MockSpeechRecognitionBubble::set_type(
    205       MockSpeechRecognitionBubble::BUBBLE_TEST_CLICK_TRY_AGAIN);
    206 
    207   controller_->CreateBubble(kBubbleSessionId, 1, 1, gfx::Rect(1, 1));
    208   base::RunLoop().RunUntilIdle();
    209   EXPECT_FALSE(cancel_clicked_);
    210   EXPECT_TRUE(try_again_clicked_);
    211   EXPECT_FALSE(focus_changed_);
    212   controller_->CloseBubble();
    213 }
    214 
    215 }  // namespace speech
    216