普通文本  |  291行  |  10.96 KB

// Copyright 2014 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 "athena/wm/window_list_provider_impl.h"

#include <algorithm>

#include "athena/test/athena_test_base.h"
#include "athena/wm/public/window_list_provider_observer.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"

namespace athena {

namespace {

bool AreWindowListsEqual(const aura::Window::Windows& one,
                         const aura::Window::Windows& two) {
  return one.size() == two.size() &&
         std::equal(one.begin(), one.end(), two.begin());
}

scoped_ptr<aura::Window> CreateWindow(aura::WindowDelegate* delegate,
                                      ui::wm::WindowType window_type) {
  scoped_ptr<aura::Window> window(new aura::Window(delegate));
  window->SetType(window_type);
  window->Init(aura::WINDOW_LAYER_SOLID_COLOR);
  return window.Pass();
}

// Return a string which defines the order of windows in |now| using the indices
// of |original|. The string will then have the lowest/oldest window on the left
// and the highest / newest on the right.
std::string GetWindowOrder(const aura::Window::Windows& original,
                           const aura::Window::Windows& now) {
  if (original.size() != now.size())
    return "size has changed.";
  std::string output;
  for (aura::Window::Windows::const_iterator it = now.begin();
       it != now.end(); ++it) {
    for (size_t i = 0; i < original.size(); i++) {
      if ((*it) == original[i]) {
        output += (output.size() ? " " : std::string()) +
                  std::to_string(i + 1);
        break;
      }
    }
  }
  return output;
}

class WindowListObserver : public WindowListProviderObserver {
 public:
  explicit WindowListObserver(WindowListProvider* provider)
      : calls_(0), window_removal_calls_(0), provider_(provider) {
    provider_->AddObserver(this);
  }
  virtual ~WindowListObserver() {
    provider_->RemoveObserver(this);
  }

  int calls() const { return calls_; }
  int window_removal_calls() const { return window_removal_calls_; }

  // WindowListProviderObserver:
  virtual void OnWindowStackingChanged() OVERRIDE {
    calls_++;
  }

  virtual void OnWindowRemoved(aura::Window* removed_window,
                               int index) OVERRIDE {
    window_removal_calls_++;
  }

 private:
  // The number of calls to the observer.
  int calls_;
  int window_removal_calls_;

  // The associated WindowListProvider which is observed.
  WindowListProvider* provider_;

  DISALLOW_COPY_AND_ASSIGN(WindowListObserver);
};


}  // namespace

typedef test::AthenaTestBase WindowListProviderImplTest;

// Tests that the order of windows match the stacking order of the windows in
// the container, even after the order is changed through the aura Window API.
TEST_F(WindowListProviderImplTest, StackingOrder) {
  aura::test::TestWindowDelegate delegate;
  scoped_ptr<aura::Window> container(new aura::Window(&delegate));
  scoped_ptr<aura::Window> first =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> second =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> third =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  container->AddChild(first.get());
  container->AddChild(second.get());
  container->AddChild(third.get());

  scoped_ptr<WindowListProvider> list_provider(
      new WindowListProviderImpl(container.get()));
  EXPECT_TRUE(AreWindowListsEqual(container->children(),
                                  list_provider->GetWindowList()));

  container->StackChildAtTop(first.get());
  EXPECT_TRUE(AreWindowListsEqual(container->children(),
                                  list_provider->GetWindowList()));
  EXPECT_EQ(first.get(), container->children().back());
}

// Tests that only normal windows of the associated container will be listed.
TEST_F(WindowListProviderImplTest, ListContainsOnlyNormalWindows) {
  aura::test::TestWindowDelegate delegate;
  scoped_ptr<aura::Window> container(new aura::Window(&delegate));
  scoped_ptr<aura::Window> first =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> second =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_POPUP);
  scoped_ptr<aura::Window> third =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> fourth =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_MENU);
  container->AddChild(first.get());
  container->AddChild(second.get());
  container->AddChild(third.get());
  container->AddChild(fourth.get());

  scoped_ptr<WindowListProvider> list_provider(
      new WindowListProviderImpl(container.get()));

  const aura::Window::Windows& list = list_provider->GetWindowList();
  EXPECT_EQ(list.end(), std::find(list.begin(), list.end(), second.get()));
  EXPECT_EQ(list.end(), std::find(list.begin(), list.end(), fourth.get()));
  EXPECT_NE(list.end(), std::find(list.begin(), list.end(), first.get()));
  EXPECT_NE(list.end(), std::find(list.begin(), list.end(), third.get()));
}

// Testing that IsValidWidow, IsWindowInList and AddWindow work as expected.
TEST_F(WindowListProviderImplTest, SimpleChecks) {
  aura::test::TestWindowDelegate delegate;
  scoped_ptr<aura::Window> container(new aura::Window(&delegate));

  scoped_ptr<aura::Window> normal_window =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> popup_window =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_POPUP);
  scoped_ptr<aura::Window> menu_window =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_MENU);

  scoped_ptr<WindowListProvider> list_provider(
      new WindowListProviderImpl(container.get()));

  // Check which windows are valid and which are not.
  EXPECT_TRUE(list_provider->IsValidWindow(normal_window.get()));
  EXPECT_FALSE(list_provider->IsValidWindow(popup_window.get()));
  EXPECT_FALSE(list_provider->IsValidWindow(menu_window.get()));

  // Check that no window is currently in the list.
  EXPECT_FALSE(list_provider->IsWindowInList(normal_window.get()));
  EXPECT_FALSE(list_provider->IsWindowInList(popup_window.get()));
  EXPECT_FALSE(list_provider->IsWindowInList(menu_window.get()));

  // Check that adding the window will add it to the list.
  container->AddChild(normal_window.get());
  EXPECT_TRUE(list_provider->IsWindowInList(normal_window.get()));
}

// Testing that window ordering functions work as expected.
TEST_F(WindowListProviderImplTest, TestWindowOrderingFunctions) {
  aura::test::TestWindowDelegate delegate;
  scoped_ptr<aura::Window> container(new aura::Window(&delegate));

  scoped_ptr<aura::Window> window1 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> window2 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> window3 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);

  scoped_ptr<WindowListProvider> list_provider(
      new WindowListProviderImpl(container.get()));
  scoped_ptr<WindowListObserver> observer(
      new WindowListObserver(list_provider.get()));

  EXPECT_FALSE(list_provider->IsWindowInList(window1.get()));
  EXPECT_FALSE(list_provider->IsWindowInList(window2.get()));
  EXPECT_FALSE(list_provider->IsWindowInList(window3.get()));

  // Add the windows.
  container->AddChild(window1.get());
  container->AddChild(window2.get());
  container->AddChild(window3.get());
  // Make a copy of the window-list in the original order.
  aura::Window::Windows original_order = list_provider->GetWindowList();
  ASSERT_EQ(3U, original_order.size());
  EXPECT_EQ(original_order[0], window1.get());
  EXPECT_EQ(original_order[1], window2.get());
  EXPECT_EQ(original_order[2], window3.get());

  EXPECT_EQ(0, observer.get()->calls());

  // Move 1 (from the back) in front of 2.
  list_provider->StackWindowFrontOf(window1.get(), window2.get());
  EXPECT_EQ("2 1 3", GetWindowOrder(original_order,
                                    list_provider->GetWindowList()));
  EXPECT_EQ(1, observer->calls());

  // Move 3 (from the front) in front of 2.
  list_provider->StackWindowFrontOf(window3.get(), window2.get());
  EXPECT_EQ("2 3 1", GetWindowOrder(original_order,
                                    list_provider->GetWindowList()));
  EXPECT_EQ(2, observer->calls());

  // Move 1 (from the front) behind 2.
  list_provider->StackWindowBehindTo(window1.get(), window2.get());
  EXPECT_EQ("1 2 3", GetWindowOrder(original_order,
                                    list_provider->GetWindowList()));
  EXPECT_EQ(3, observer->calls());

  // Move 1 (from the back) in front of 3.
  list_provider->StackWindowFrontOf(window1.get(), window3.get());
  EXPECT_EQ("2 3 1", GetWindowOrder(original_order,
                                    list_provider->GetWindowList()));
  EXPECT_EQ(4, observer->calls());

  // Test that no change should also report no call.
  list_provider->StackWindowFrontOf(window1.get(), window3.get());
  EXPECT_EQ("2 3 1", GetWindowOrder(original_order,
                                    list_provider->GetWindowList()));
  EXPECT_EQ(4, observer->calls());
  list_provider->StackWindowBehindTo(window3.get(), window1.get());
  EXPECT_EQ("2 3 1", GetWindowOrder(original_order,
                                    list_provider->GetWindowList()));
  EXPECT_EQ(4, observer->calls());
}

TEST_F(WindowListProviderImplTest, TestWindowRemovalNotification) {
  aura::test::TestWindowDelegate delegate;
  scoped_ptr<aura::Window> container(new aura::Window(&delegate));

  scoped_ptr<aura::Window> window1 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> window2 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> window3 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_NORMAL);
  scoped_ptr<aura::Window> window4 =
      CreateWindow(&delegate, ui::wm::WINDOW_TYPE_POPUP);

  scoped_ptr<WindowListProvider> list_provider(
      new WindowListProviderImpl(container.get()));
  scoped_ptr<WindowListObserver> observer(
      new WindowListObserver(list_provider.get()));

  // Add the windows.
  container->AddChild(window1.get());
  container->AddChild(window2.get());
  container->AddChild(window3.get());
  container->AddChild(window4.get());
  // The popup-window (window4) should not be included in the window-list.
  ASSERT_EQ(3U, list_provider->GetWindowList().size());
  EXPECT_EQ(0, observer->window_removal_calls());
  EXPECT_FALSE(list_provider->IsWindowInList(window4.get()));

  // Destroying the popup window should not trigger the remove notification.
  window4.reset();
  ASSERT_EQ(3U, list_provider->GetWindowList().size());
  EXPECT_EQ(0, observer->window_removal_calls());

  window2.reset();
  ASSERT_EQ(2U, list_provider->GetWindowList().size());
  EXPECT_EQ(1, observer->window_removal_calls());

  window1.reset();
  ASSERT_EQ(1U, list_provider->GetWindowList().size());
  EXPECT_EQ(2, observer->window_removal_calls());

  window3.reset();
  ASSERT_EQ(0U, list_provider->GetWindowList().size());
  EXPECT_EQ(3, observer->window_removal_calls());
}

}  // namespace athena