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