Home | History | Annotate | Download | only in tests
      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 "ppapi/tests/test_view.h"
      6 
      7 #include <sstream>
      8 
      9 #include "ppapi/c/pp_time.h"
     10 #include "ppapi/c/dev/ppb_testing_dev.h"
     11 #include "ppapi/cpp/completion_callback.h"
     12 #include "ppapi/tests/testing_instance.h"
     13 
     14 REGISTER_TEST_CASE(View);
     15 
     16 // When waiting for view changed events, wait no longer than this.
     17 static int kViewChangeTimeoutSec = 5;
     18 
     19 TestView::TestView(TestingInstance* instance)
     20     : TestCase(instance),
     21       post_quit_on_view_changed_(false) {
     22 }
     23 
     24 void TestView::DidChangeView(const pp::View& view) {
     25   last_view_ = view;
     26   page_visibility_log_.push_back(view.IsPageVisible());
     27 
     28   if (post_quit_on_view_changed_) {
     29     post_quit_on_view_changed_ = false;
     30     testing_interface_->QuitMessageLoop(instance_->pp_instance());
     31   }
     32 }
     33 
     34 bool TestView::Init() {
     35   return CheckTestingInterface();
     36 }
     37 
     38 void TestView::RunTests(const std::string& filter) {
     39   RUN_TEST(CreatedVisible, filter);
     40   RUN_TEST(CreatedInvisible, filter);
     41   RUN_TEST(PageHideShow, filter);
     42   RUN_TEST(SizeChange, filter);
     43   RUN_TEST(ClipChange, filter);
     44 }
     45 
     46 bool TestView::WaitUntilViewChanged() {
     47   // Schedule a callback so this step times out if we don't get a ViewChanged
     48   // in a reasonable amount of time.
     49   pp::CompletionCallbackFactory<TestView> factory(this);
     50   pp::CompletionCallback timeout =
     51       factory.NewCallback(&TestView::QuitMessageLoop);
     52   pp::Module::Get()->core()->CallOnMainThread(
     53       kViewChangeTimeoutSec * 1000, timeout);
     54 
     55   size_t old_page_visibility_change_count = page_visibility_log_.size();
     56 
     57   // Run a nested message loop. It will exit either on ViewChanged or if the
     58   // timeout happens.
     59   post_quit_on_view_changed_ = true;
     60   testing_interface_->RunMessageLoop(instance_->pp_instance());
     61   post_quit_on_view_changed_ = false;
     62 
     63   // We know we got a view changed event if something was appended to the log.
     64   return page_visibility_log_.size() > old_page_visibility_change_count;
     65 }
     66 
     67 void TestView::QuitMessageLoop(int32_t result) {
     68   testing_interface_->QuitMessageLoop(instance_->pp_instance());
     69 }
     70 
     71 std::string TestView::TestCreatedVisible() {
     72   ASSERT_FALSE(page_visibility_log_.empty());
     73   ASSERT_TRUE(page_visibility_log_[0]);
     74   PASS();
     75 }
     76 
     77 std::string TestView::TestCreatedInvisible() {
     78   ASSERT_FALSE(page_visibility_log_.empty());
     79 
     80   if (page_visibility_log_[0]) {
     81     // Add more error message since this test has some extra requirements.
     82     instance_->AppendError("Initial page is set to visible. NOTE: "
     83         "This test must be run in a background tab. "
     84         "Either run in the UI test which does this, or you can middle-click "
     85         "on the test link to run manually.");
     86   }
     87   ASSERT_FALSE(page_visibility_log_[0]);
     88   PASS();
     89 }
     90 
     91 std::string TestView::TestPageHideShow() {
     92   // Initial state should be visible.
     93   ASSERT_FALSE(page_visibility_log_.empty());
     94   ASSERT_TRUE(page_visibility_log_[0]);
     95 
     96   // Now that we're alive, tell the test knows it can change our visibility.
     97   instance_->ReportProgress("TestPageHideShow:Created");
     98 
     99   // Wait until we get a hide event, being careful to handle spurious
    100   // notifications of ViewChanged.
    101   PP_Time begin_time = pp::Module::Get()->core()->GetTime();
    102   while (WaitUntilViewChanged() &&
    103          page_visibility_log_[page_visibility_log_.size() - 1] &&
    104          pp::Module::Get()->core()->GetTime() - begin_time <
    105              kViewChangeTimeoutSec) {
    106   }
    107   if (page_visibility_log_[page_visibility_log_.size() - 1]) {
    108     // Didn't get a view changed event that changed visibility (though there
    109     // may have been some that didn't change visibility).
    110     // Add more error message since this test has some extra requirements.
    111     return "Didn't receive a hide event in timeout. NOTE: "
    112         "This test requires tab visibility to change and won't pass if you "
    113         "just run it in a browser. Normally the UI test should handle "
    114         "this. You can also run manually by waiting 2 secs, creating a new "
    115         "tab, waiting 2 more secs, and closing the new tab.";
    116   }
    117 
    118   // Tell the test so it can show us again.
    119   instance_->ReportProgress("TestPageHideShow:Hidden");
    120 
    121   // Wait until we get a show event.
    122   begin_time = pp::Module::Get()->core()->GetTime();
    123   while (WaitUntilViewChanged() &&
    124          !page_visibility_log_[page_visibility_log_.size() - 1] &&
    125          pp::Module::Get()->core()->GetTime() - begin_time <
    126              kViewChangeTimeoutSec) {
    127   }
    128   ASSERT_TRUE(page_visibility_log_[page_visibility_log_.size() - 1]);
    129 
    130   PASS();
    131 }
    132 
    133 std::string TestView::TestSizeChange() {
    134   pp::Rect original_rect = last_view_.GetRect();
    135 
    136   pp::Rect desired_rect = original_rect;
    137   desired_rect.set_width(original_rect.width() + 10);
    138   desired_rect.set_height(original_rect.height() + 12);
    139 
    140   std::ostringstream script_stream;
    141   script_stream << "var plugin = document.getElementById('plugin');";
    142   script_stream << "plugin.setAttribute('width', "
    143                 << desired_rect.width() << ");";
    144   script_stream << "plugin.setAttribute('height', "
    145                 << desired_rect.height() << ");";
    146 
    147   instance_->EvalScript(script_stream.str());
    148 
    149   PP_Time begin_time = pp::Module::Get()->core()->GetTime();
    150   while (WaitUntilViewChanged() && last_view_.GetRect() != desired_rect &&
    151          pp::Module::Get()->core()->GetTime() - begin_time <
    152              kViewChangeTimeoutSec) {
    153   }
    154   ASSERT_TRUE(last_view_.GetRect() == desired_rect);
    155 
    156   PASS();
    157 }
    158 
    159 std::string TestView::TestClipChange() {
    160   pp::Rect original_rect = last_view_.GetRect();
    161 
    162   // Original clip should be the full frame.
    163   pp::Rect original_clip = last_view_.GetClipRect();
    164   ASSERT_TRUE(original_clip.x() == 0);
    165   ASSERT_TRUE(original_clip.y() == 0);
    166   ASSERT_TRUE(original_clip.width() == original_rect.width());
    167   ASSERT_TRUE(original_clip.height() == original_rect.height());
    168 
    169   int clip_amount = original_rect.height() / 2;
    170 
    171   // It might be nice to set the position to be absolute and set the location,
    172   // but this will cause WebKit to actually tear down the plugin and recreate
    173   // it. So instead we add a big div to cause the document to be scrollable,
    174   // and scroll it down.
    175   std::ostringstream script_stream;
    176   script_stream
    177       << "var big = document.createElement('div');"
    178       << "big.setAttribute('style', 'position:absolute; left:100px; "
    179                                     "top:0px; width:1px; height:5000px;');"
    180       << "document.body.appendChild(big);"
    181       << "window.scrollBy(0, " << original_rect.y() + clip_amount << ");";
    182 
    183   instance_->EvalScript(script_stream.str());
    184 
    185   pp::Rect desired_clip = original_clip;
    186   desired_clip.set_y(clip_amount);
    187   desired_clip.set_height(desired_clip.height() - desired_clip.y());
    188 
    189   PP_Time begin_time = pp::Module::Get()->core()->GetTime();
    190   while (WaitUntilViewChanged() && last_view_.GetClipRect() != desired_clip &&
    191          pp::Module::Get()->core()->GetTime() - begin_time <
    192              kViewChangeTimeoutSec) {
    193   }
    194   ASSERT_TRUE(last_view_.GetClipRect() == desired_clip);
    195   PASS();
    196 }
    197