diff options
Diffstat (limited to 'components/mus/public/cpp/tests')
-rw-r--r-- | components/mus/public/cpp/tests/BUILD.gn | 10 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/run_all_unittests.cc | 6 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/view_manager_test_suite.h | 27 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/view_unittest.cc | 874 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/window_server_test_base.cc (renamed from components/mus/public/cpp/tests/view_manager_test_base.cc) | 40 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/window_server_test_base.h (renamed from components/mus/public/cpp/tests/view_manager_test_base.h) | 46 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/window_server_test_suite.cc (renamed from components/mus/public/cpp/tests/view_manager_test_suite.cc) | 8 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/window_server_test_suite.h | 27 | ||||
-rw-r--r-- | components/mus/public/cpp/tests/window_unittest.cc | 875 |
9 files changed, 957 insertions, 956 deletions
diff --git a/components/mus/public/cpp/tests/BUILD.gn b/components/mus/public/cpp/tests/BUILD.gn index c582994..b9ba5d0 100644 --- a/components/mus/public/cpp/tests/BUILD.gn +++ b/components/mus/public/cpp/tests/BUILD.gn @@ -9,8 +9,8 @@ source_set("test_support") { testonly = true sources = [ - "view_manager_test_base.cc", - "view_manager_test_base.h", + "window_server_test_base.cc", + "window_server_test_base.h", ] deps = [ @@ -26,9 +26,9 @@ source_set("test_support") { test("mojo_view_manager_lib_unittests") { sources = [ "run_all_unittests.cc", - "view_manager_test_suite.cc", - "view_manager_test_suite.h", - "view_unittest.cc", + "window_server_test_suite.cc", + "window_server_test_suite.h", + "window_unittest.cc", ] deps = [ diff --git a/components/mus/public/cpp/tests/run_all_unittests.cc b/components/mus/public/cpp/tests/run_all_unittests.cc index ee82a07..1af6dbd 100644 --- a/components/mus/public/cpp/tests/run_all_unittests.cc +++ b/components/mus/public/cpp/tests/run_all_unittests.cc @@ -4,12 +4,12 @@ #include "base/bind.h" #include "base/test/launcher/unit_test_launcher.h" -#include "components/mus/public/cpp/tests/view_manager_test_suite.h" +#include "components/mus/public/cpp/tests/window_server_test_suite.h" int main(int argc, char** argv) { - mus::ViewManagerTestSuite test_suite(argc, argv); + mus::WindowServerTestSuite test_suite(argc, argv); return base::LaunchUnitTests(argc, argv, - base::Bind(&mus::ViewManagerTestSuite::Run, + base::Bind(&mus::WindowServerTestSuite::Run, base::Unretained(&test_suite))); } diff --git a/components/mus/public/cpp/tests/view_manager_test_suite.h b/components/mus/public/cpp/tests/view_manager_test_suite.h deleted file mode 100644 index b68bb2f..0000000 --- a/components/mus/public/cpp/tests/view_manager_test_suite.h +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -#ifndef COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_ -#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_ - -#include "base/test/test_suite.h" -#include "third_party/mojo/src/mojo/public/cpp/system/macros.h" - -namespace mus { - -class ViewManagerTestSuite : public base::TestSuite { - public: - ViewManagerTestSuite(int argc, char** argv); - ~ViewManagerTestSuite() override; - - protected: - void Initialize() override; - - private: - MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTestSuite); -}; - -} // namespace mus - -#endif // COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_ diff --git a/components/mus/public/cpp/tests/view_unittest.cc b/components/mus/public/cpp/tests/view_unittest.cc deleted file mode 100644 index c991ca3..0000000 --- a/components/mus/public/cpp/tests/view_unittest.cc +++ /dev/null @@ -1,874 +0,0 @@ -// 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 "components/mus/public/cpp/view.h" - -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "components/mus/public/cpp/lib/view_private.h" -#include "components/mus/public/cpp/util.h" -#include "components/mus/public/cpp/view_observer.h" -#include "components/mus/public/cpp/view_property.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mus { - -// View ------------------------------------------------------------------------ - -typedef testing::Test ViewTest; - -// Subclass with public ctor/dtor. -class TestView : public View { - public: - TestView() { ViewPrivate(this).set_id(1); } - ~TestView() {} - - private: - MOJO_DISALLOW_COPY_AND_ASSIGN(TestView); -}; - -TEST_F(ViewTest, AddChild) { - TestView v1; - TestView v11; - v1.AddChild(&v11); - EXPECT_EQ(1U, v1.children().size()); -} - -TEST_F(ViewTest, RemoveChild) { - TestView v1; - TestView v11; - v1.AddChild(&v11); - EXPECT_EQ(1U, v1.children().size()); - v1.RemoveChild(&v11); - EXPECT_EQ(0U, v1.children().size()); -} - -TEST_F(ViewTest, Reparent) { - TestView v1; - TestView v2; - TestView v11; - v1.AddChild(&v11); - EXPECT_EQ(1U, v1.children().size()); - v2.AddChild(&v11); - EXPECT_EQ(1U, v2.children().size()); - EXPECT_EQ(0U, v1.children().size()); -} - -TEST_F(ViewTest, Contains) { - TestView v1; - - // Direct descendant. - TestView v11; - v1.AddChild(&v11); - EXPECT_TRUE(v1.Contains(&v11)); - - // Indirect descendant. - TestView v111; - v11.AddChild(&v111); - EXPECT_TRUE(v1.Contains(&v111)); -} - -TEST_F(ViewTest, GetChildById) { - TestView v1; - ViewPrivate(&v1).set_id(1); - TestView v11; - ViewPrivate(&v11).set_id(11); - v1.AddChild(&v11); - TestView v111; - ViewPrivate(&v111).set_id(111); - v11.AddChild(&v111); - - // Find direct & indirect descendents. - EXPECT_EQ(&v11, v1.GetChildById(v11.id())); - EXPECT_EQ(&v111, v1.GetChildById(v111.id())); -} - -TEST_F(ViewTest, DrawnAndVisible) { - TestView v1; - EXPECT_TRUE(v1.visible()); - EXPECT_FALSE(v1.IsDrawn()); - - ViewPrivate(&v1).set_drawn(true); - - TestView v11; - v1.AddChild(&v11); - EXPECT_TRUE(v11.visible()); - EXPECT_TRUE(v11.IsDrawn()); - - v1.RemoveChild(&v11); - EXPECT_TRUE(v11.visible()); - EXPECT_FALSE(v11.IsDrawn()); -} - -namespace { -DEFINE_VIEW_PROPERTY_KEY(int, kIntKey, -2); -DEFINE_VIEW_PROPERTY_KEY(const char*, kStringKey, "squeamish"); -} - -TEST_F(ViewTest, Property) { - TestView v; - - // Non-existent properties should return the default values. - EXPECT_EQ(-2, v.GetLocalProperty(kIntKey)); - EXPECT_EQ(std::string("squeamish"), v.GetLocalProperty(kStringKey)); - - // A set property value should be returned again (even if it's the default - // value). - v.SetLocalProperty(kIntKey, INT_MAX); - EXPECT_EQ(INT_MAX, v.GetLocalProperty(kIntKey)); - v.SetLocalProperty(kIntKey, -2); - EXPECT_EQ(-2, v.GetLocalProperty(kIntKey)); - v.SetLocalProperty(kIntKey, INT_MIN); - EXPECT_EQ(INT_MIN, v.GetLocalProperty(kIntKey)); - - v.SetLocalProperty(kStringKey, static_cast<const char*>(NULL)); - EXPECT_EQ(NULL, v.GetLocalProperty(kStringKey)); - v.SetLocalProperty(kStringKey, "squeamish"); - EXPECT_EQ(std::string("squeamish"), v.GetLocalProperty(kStringKey)); - v.SetLocalProperty(kStringKey, "ossifrage"); - EXPECT_EQ(std::string("ossifrage"), v.GetLocalProperty(kStringKey)); - - // ClearProperty should restore the default value. - v.ClearLocalProperty(kIntKey); - EXPECT_EQ(-2, v.GetLocalProperty(kIntKey)); - v.ClearLocalProperty(kStringKey); - EXPECT_EQ(std::string("squeamish"), v.GetLocalProperty(kStringKey)); -} - -namespace { - -class TestProperty { - public: - TestProperty() {} - virtual ~TestProperty() { last_deleted_ = this; } - static TestProperty* last_deleted() { return last_deleted_; } - - private: - static TestProperty* last_deleted_; - MOJO_DISALLOW_COPY_AND_ASSIGN(TestProperty); -}; - -TestProperty* TestProperty::last_deleted_ = NULL; - -DEFINE_OWNED_VIEW_PROPERTY_KEY(TestProperty, kOwnedKey, NULL); - -} // namespace - -TEST_F(ViewTest, OwnedProperty) { - TestProperty* p3 = NULL; - { - TestView v; - EXPECT_EQ(NULL, v.GetLocalProperty(kOwnedKey)); - TestProperty* p1 = new TestProperty(); - v.SetLocalProperty(kOwnedKey, p1); - EXPECT_EQ(p1, v.GetLocalProperty(kOwnedKey)); - EXPECT_EQ(NULL, TestProperty::last_deleted()); - - TestProperty* p2 = new TestProperty(); - v.SetLocalProperty(kOwnedKey, p2); - EXPECT_EQ(p2, v.GetLocalProperty(kOwnedKey)); - EXPECT_EQ(p1, TestProperty::last_deleted()); - - v.ClearLocalProperty(kOwnedKey); - EXPECT_EQ(NULL, v.GetLocalProperty(kOwnedKey)); - EXPECT_EQ(p2, TestProperty::last_deleted()); - - p3 = new TestProperty(); - v.SetLocalProperty(kOwnedKey, p3); - EXPECT_EQ(p3, v.GetLocalProperty(kOwnedKey)); - EXPECT_EQ(p2, TestProperty::last_deleted()); - } - - EXPECT_EQ(p3, TestProperty::last_deleted()); -} - -// ViewObserver -------------------------------------------------------- - -typedef testing::Test ViewObserverTest; - -bool TreeChangeParamsMatch(const ViewObserver::TreeChangeParams& lhs, - const ViewObserver::TreeChangeParams& rhs) { - return lhs.target == rhs.target && lhs.old_parent == rhs.old_parent && - lhs.new_parent == rhs.new_parent && lhs.receiver == rhs.receiver; -} - -class TreeChangeObserver : public ViewObserver { - public: - explicit TreeChangeObserver(View* observee) : observee_(observee) { - observee_->AddObserver(this); - } - ~TreeChangeObserver() override { observee_->RemoveObserver(this); } - - void Reset() { received_params_.clear(); } - - const std::vector<TreeChangeParams>& received_params() { - return received_params_; - } - - private: - // Overridden from ViewObserver: - void OnTreeChanging(const TreeChangeParams& params) override { - received_params_.push_back(params); - } - void OnTreeChanged(const TreeChangeParams& params) override { - received_params_.push_back(params); - } - - View* observee_; - std::vector<TreeChangeParams> received_params_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver); -}; - -// Adds/Removes v11 to v1. -TEST_F(ViewObserverTest, TreeChange_SimpleAddRemove) { - TestView v1; - TreeChangeObserver o1(&v1); - EXPECT_TRUE(o1.received_params().empty()); - - TestView v11; - TreeChangeObserver o11(&v11); - EXPECT_TRUE(o11.received_params().empty()); - - // Add. - - v1.AddChild(&v11); - - EXPECT_EQ(2U, o1.received_params().size()); - ViewObserver::TreeChangeParams p1; - p1.target = &v11; - p1.receiver = &v1; - p1.old_parent = NULL; - p1.new_parent = &v1; - EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); - - EXPECT_EQ(2U, o11.received_params().size()); - ViewObserver::TreeChangeParams p11 = p1; - p11.receiver = &v11; - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); - - o1.Reset(); - o11.Reset(); - EXPECT_TRUE(o1.received_params().empty()); - EXPECT_TRUE(o11.received_params().empty()); - - // Remove. - - v1.RemoveChild(&v11); - - EXPECT_EQ(2U, o1.received_params().size()); - p1.target = &v11; - p1.receiver = &v1; - p1.old_parent = &v1; - p1.new_parent = NULL; - EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); - - EXPECT_EQ(2U, o11.received_params().size()); - p11 = p1; - p11.receiver = &v11; - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); -} - -// Creates these two trees: -// v1 -// +- v11 -// v111 -// +- v1111 -// +- v1112 -// Then adds/removes v111 from v11. -TEST_F(ViewObserverTest, TreeChange_NestedAddRemove) { - TestView v1, v11, v111, v1111, v1112; - - // Root tree. - v1.AddChild(&v11); - - // Tree to be attached. - v111.AddChild(&v1111); - v111.AddChild(&v1112); - - TreeChangeObserver o1(&v1), o11(&v11), o111(&v111), o1111(&v1111), - o1112(&v1112); - ViewObserver::TreeChangeParams p1, p11, p111, p1111, p1112; - - // Add. - - v11.AddChild(&v111); - - EXPECT_EQ(2U, o1.received_params().size()); - p1.target = &v111; - p1.receiver = &v1; - p1.old_parent = NULL; - p1.new_parent = &v11; - EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); - - EXPECT_EQ(2U, o11.received_params().size()); - p11 = p1; - p11.receiver = &v11; - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); - - EXPECT_EQ(2U, o111.received_params().size()); - p111 = p11; - p111.receiver = &v111; - EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); - - EXPECT_EQ(2U, o1111.received_params().size()); - p1111 = p111; - p1111.receiver = &v1111; - EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back())); - - EXPECT_EQ(2U, o1112.received_params().size()); - p1112 = p111; - p1112.receiver = &v1112; - EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back())); - - // Remove. - o1.Reset(); - o11.Reset(); - o111.Reset(); - o1111.Reset(); - o1112.Reset(); - EXPECT_TRUE(o1.received_params().empty()); - EXPECT_TRUE(o11.received_params().empty()); - EXPECT_TRUE(o111.received_params().empty()); - EXPECT_TRUE(o1111.received_params().empty()); - EXPECT_TRUE(o1112.received_params().empty()); - - v11.RemoveChild(&v111); - - EXPECT_EQ(2U, o1.received_params().size()); - p1.target = &v111; - p1.receiver = &v1; - p1.old_parent = &v11; - p1.new_parent = NULL; - EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); - - EXPECT_EQ(2U, o11.received_params().size()); - p11 = p1; - p11.receiver = &v11; - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); - - EXPECT_EQ(2U, o111.received_params().size()); - p111 = p11; - p111.receiver = &v111; - EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); - - EXPECT_EQ(2U, o1111.received_params().size()); - p1111 = p111; - p1111.receiver = &v1111; - EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back())); - - EXPECT_EQ(2U, o1112.received_params().size()); - p1112 = p111; - p1112.receiver = &v1112; - EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back())); -} - -TEST_F(ViewObserverTest, TreeChange_Reparent) { - TestView v1, v11, v12, v111; - v1.AddChild(&v11); - v1.AddChild(&v12); - v11.AddChild(&v111); - - TreeChangeObserver o1(&v1), o11(&v11), o12(&v12), o111(&v111); - - // Reparent. - v12.AddChild(&v111); - - // v1 (root) should see both changing and changed notifications. - EXPECT_EQ(4U, o1.received_params().size()); - ViewObserver::TreeChangeParams p1; - p1.target = &v111; - p1.receiver = &v1; - p1.old_parent = &v11; - p1.new_parent = &v12; - EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); - - // v11 should see changing notifications. - EXPECT_EQ(2U, o11.received_params().size()); - ViewObserver::TreeChangeParams p11; - p11 = p1; - p11.receiver = &v11; - EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); - - // v12 should see changed notifications. - EXPECT_EQ(2U, o12.received_params().size()); - ViewObserver::TreeChangeParams p12; - p12 = p1; - p12.receiver = &v12; - EXPECT_TRUE(TreeChangeParamsMatch(p12, o12.received_params().back())); - - // v111 should see both changing and changed notifications. - EXPECT_EQ(2U, o111.received_params().size()); - ViewObserver::TreeChangeParams p111; - p111 = p1; - p111.receiver = &v111; - EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); - EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); -} - -namespace { - -class OrderChangeObserver : public ViewObserver { - public: - struct Change { - View* view; - View* relative_view; - mojo::OrderDirection direction; - }; - typedef std::vector<Change> Changes; - - explicit OrderChangeObserver(View* observee) : observee_(observee) { - observee_->AddObserver(this); - } - ~OrderChangeObserver() override { observee_->RemoveObserver(this); } - - Changes GetAndClearChanges() { - Changes changes; - changes_.swap(changes); - return changes; - } - - private: - // Overridden from ViewObserver: - void OnViewReordering(View* view, - View* relative_view, - mojo::OrderDirection direction) override { - OnViewReordered(view, relative_view, direction); - } - - void OnViewReordered(View* view, - View* relative_view, - mojo::OrderDirection direction) override { - Change change; - change.view = view; - change.relative_view = relative_view; - change.direction = direction; - changes_.push_back(change); - } - - View* observee_; - Changes changes_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); -}; - -} // namespace - -TEST_F(ViewObserverTest, Order) { - TestView v1, v11, v12, v13; - v1.AddChild(&v11); - v1.AddChild(&v12); - v1.AddChild(&v13); - - // Order: v11, v12, v13 - EXPECT_EQ(3U, v1.children().size()); - EXPECT_EQ(&v11, v1.children().front()); - EXPECT_EQ(&v13, v1.children().back()); - - { - OrderChangeObserver observer(&v11); - - // Move v11 to front. - // Resulting order: v12, v13, v11 - v11.MoveToFront(); - EXPECT_EQ(&v12, v1.children().front()); - EXPECT_EQ(&v11, v1.children().back()); - - OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(2U, changes.size()); - EXPECT_EQ(&v11, changes[0].view); - EXPECT_EQ(&v13, changes[0].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction); - - EXPECT_EQ(&v11, changes[1].view); - EXPECT_EQ(&v13, changes[1].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction); - } - - { - OrderChangeObserver observer(&v11); - - // Move v11 to back. - // Resulting order: v11, v12, v13 - v11.MoveToBack(); - EXPECT_EQ(&v11, v1.children().front()); - EXPECT_EQ(&v13, v1.children().back()); - - OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(2U, changes.size()); - EXPECT_EQ(&v11, changes[0].view); - EXPECT_EQ(&v12, changes[0].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction); - - EXPECT_EQ(&v11, changes[1].view); - EXPECT_EQ(&v12, changes[1].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction); - } - - { - OrderChangeObserver observer(&v11); - - // Move v11 above v12. - // Resulting order: v12. v11, v13 - v11.Reorder(&v12, mojo::ORDER_DIRECTION_ABOVE); - EXPECT_EQ(&v12, v1.children().front()); - EXPECT_EQ(&v13, v1.children().back()); - - OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(2U, changes.size()); - EXPECT_EQ(&v11, changes[0].view); - EXPECT_EQ(&v12, changes[0].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction); - - EXPECT_EQ(&v11, changes[1].view); - EXPECT_EQ(&v12, changes[1].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction); - } - - { - OrderChangeObserver observer(&v11); - - // Move v11 below v12. - // Resulting order: v11, v12, v13 - v11.Reorder(&v12, mojo::ORDER_DIRECTION_BELOW); - EXPECT_EQ(&v11, v1.children().front()); - EXPECT_EQ(&v13, v1.children().back()); - - OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(2U, changes.size()); - EXPECT_EQ(&v11, changes[0].view); - EXPECT_EQ(&v12, changes[0].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction); - - EXPECT_EQ(&v11, changes[1].view); - EXPECT_EQ(&v12, changes[1].relative_view); - EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction); - } -} - -namespace { - -typedef std::vector<std::string> Changes; - -std::string ViewIdToString(Id id) { - return (id == 0) ? "null" - : base::StringPrintf("%d,%d", HiWord(id), LoWord(id)); -} - -std::string RectToString(const mojo::Rect& rect) { - return base::StringPrintf("%d,%d %dx%d", rect.x, rect.y, rect.width, - rect.height); -} - -class BoundsChangeObserver : public ViewObserver { - public: - explicit BoundsChangeObserver(View* view) : view_(view) { - view_->AddObserver(this); - } - ~BoundsChangeObserver() override { view_->RemoveObserver(this); } - - Changes GetAndClearChanges() { - Changes changes; - changes.swap(changes_); - return changes; - } - - private: - // Overridden from ViewObserver: - void OnViewBoundsChanging(View* view, - const mojo::Rect& old_bounds, - const mojo::Rect& new_bounds) override { - changes_.push_back(base::StringPrintf( - "view=%s old_bounds=%s new_bounds=%s phase=changing", - ViewIdToString(view->id()).c_str(), RectToString(old_bounds).c_str(), - RectToString(new_bounds).c_str())); - } - void OnViewBoundsChanged(View* view, - const mojo::Rect& old_bounds, - const mojo::Rect& new_bounds) override { - changes_.push_back(base::StringPrintf( - "view=%s old_bounds=%s new_bounds=%s phase=changed", - ViewIdToString(view->id()).c_str(), RectToString(old_bounds).c_str(), - RectToString(new_bounds).c_str())); - } - - View* view_; - Changes changes_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); -}; - -} // namespace - -TEST_F(ViewObserverTest, SetBounds) { - TestView v1; - { - BoundsChangeObserver observer(&v1); - mojo::Rect rect; - rect.width = rect.height = 100; - v1.SetBounds(rect); - - Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(2U, changes.size()); - EXPECT_EQ( - "view=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changing", - changes[0]); - EXPECT_EQ( - "view=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changed", - changes[1]); - } -} - -namespace { - -class VisibilityChangeObserver : public ViewObserver { - public: - explicit VisibilityChangeObserver(View* view) : view_(view) { - view_->AddObserver(this); - } - ~VisibilityChangeObserver() override { view_->RemoveObserver(this); } - - Changes GetAndClearChanges() { - Changes changes; - changes.swap(changes_); - return changes; - } - - private: - // Overridden from ViewObserver: - void OnViewVisibilityChanging(View* view) override { - changes_.push_back( - base::StringPrintf("view=%s phase=changing visibility=%s", - ViewIdToString(view->id()).c_str(), - view->visible() ? "true" : "false")); - } - void OnViewVisibilityChanged(View* view) override { - changes_.push_back(base::StringPrintf("view=%s phase=changed visibility=%s", - ViewIdToString(view->id()).c_str(), - view->visible() ? "true" : "false")); - } - - View* view_; - Changes changes_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); -}; - -} // namespace - -TEST_F(ViewObserverTest, SetVisible) { - TestView v1; - EXPECT_TRUE(v1.visible()); - { - // Change visibility from true to false and make sure we get notifications. - VisibilityChangeObserver observer(&v1); - v1.SetVisible(false); - - Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(2U, changes.size()); - EXPECT_EQ("view=0,1 phase=changing visibility=true", changes[0]); - EXPECT_EQ("view=0,1 phase=changed visibility=false", changes[1]); - } - { - // Set visible to existing value and verify no notifications. - VisibilityChangeObserver observer(&v1); - v1.SetVisible(false); - EXPECT_TRUE(observer.GetAndClearChanges().empty()); - } -} - -TEST_F(ViewObserverTest, SetVisibleParent) { - TestView parent; - ViewPrivate(&parent).set_id(1); - TestView child; - ViewPrivate(&child).set_id(2); - parent.AddChild(&child); - EXPECT_TRUE(parent.visible()); - EXPECT_TRUE(child.visible()); - { - // Change visibility from true to false and make sure we get notifications - // on the parent. - VisibilityChangeObserver observer(&parent); - child.SetVisible(false); - - Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(1U, changes.size()); - EXPECT_EQ("view=0,2 phase=changed visibility=false", changes[0]); - } -} - -TEST_F(ViewObserverTest, SetVisibleChild) { - TestView parent; - ViewPrivate(&parent).set_id(1); - TestView child; - ViewPrivate(&child).set_id(2); - parent.AddChild(&child); - EXPECT_TRUE(parent.visible()); - EXPECT_TRUE(child.visible()); - { - // Change visibility from true to false and make sure we get notifications - // on the child. - VisibilityChangeObserver observer(&child); - parent.SetVisible(false); - - Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(1U, changes.size()); - EXPECT_EQ("view=0,1 phase=changed visibility=false", changes[0]); - } -} - -namespace { - -class SharedPropertyChangeObserver : public ViewObserver { - public: - explicit SharedPropertyChangeObserver(View* view) : view_(view) { - view_->AddObserver(this); - } - ~SharedPropertyChangeObserver() override { view_->RemoveObserver(this); } - - Changes GetAndClearChanges() { - Changes changes; - changes.swap(changes_); - return changes; - } - - private: - // Overridden from ViewObserver: - void OnViewSharedPropertyChanged( - View* view, - const std::string& name, - const std::vector<uint8_t>* old_data, - const std::vector<uint8_t>* new_data) override { - changes_.push_back(base::StringPrintf( - "view=%s shared property changed key=%s old_value=%s new_value=%s", - ViewIdToString(view->id()).c_str(), name.c_str(), - VectorToString(old_data).c_str(), VectorToString(new_data).c_str())); - } - - std::string VectorToString(const std::vector<uint8_t>* data) { - if (!data) - return "NULL"; - std::string s; - for (char c : *data) - s += c; - return s; - } - - View* view_; - Changes changes_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver); -}; - -} // namespace - -TEST_F(ViewObserverTest, SetLocalProperty) { - TestView v1; - std::vector<uint8_t> one(1, '1'); - - { - // Change visibility from true to false and make sure we get notifications. - SharedPropertyChangeObserver observer(&v1); - v1.SetSharedProperty("one", &one); - Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(1U, changes.size()); - EXPECT_EQ( - "view=0,1 shared property changed key=one old_value=NULL new_value=1", - changes[0]); - EXPECT_EQ(1U, v1.shared_properties().size()); - } - { - // Set visible to existing value and verify no notifications. - SharedPropertyChangeObserver observer(&v1); - v1.SetSharedProperty("one", &one); - EXPECT_TRUE(observer.GetAndClearChanges().empty()); - EXPECT_EQ(1U, v1.shared_properties().size()); - } - { - // Set the value to NULL to delete it. - // Change visibility from true to false and make sure we get notifications. - SharedPropertyChangeObserver observer(&v1); - v1.SetSharedProperty("one", NULL); - Changes changes = observer.GetAndClearChanges(); - ASSERT_EQ(1U, changes.size()); - EXPECT_EQ( - "view=0,1 shared property changed key=one old_value=1 new_value=NULL", - changes[0]); - EXPECT_EQ(0U, v1.shared_properties().size()); - } - { - // Setting a null property to null shouldn't update us. - SharedPropertyChangeObserver observer(&v1); - v1.SetSharedProperty("one", NULL); - EXPECT_TRUE(observer.GetAndClearChanges().empty()); - EXPECT_EQ(0U, v1.shared_properties().size()); - } -} - -namespace { - -typedef std::pair<const void*, intptr_t> PropertyChangeInfo; - -class LocalPropertyChangeObserver : public ViewObserver { - public: - explicit LocalPropertyChangeObserver(View* view) - : view_(view), property_key_(nullptr), old_property_value_(-1) { - view_->AddObserver(this); - } - ~LocalPropertyChangeObserver() override { view_->RemoveObserver(this); } - - PropertyChangeInfo PropertyChangeInfoAndClear() { - PropertyChangeInfo result(property_key_, old_property_value_); - property_key_ = NULL; - old_property_value_ = -3; - return result; - } - - private: - void OnViewLocalPropertyChanged(View* window, - const void* key, - intptr_t old) override { - property_key_ = key; - old_property_value_ = old; - } - - View* view_; - const void* property_key_; - intptr_t old_property_value_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver); -}; - -} // namespace - -TEST_F(ViewObserverTest, LocalPropertyChanged) { - TestView v1; - LocalPropertyChangeObserver o(&v1); - - static const ViewProperty<int> prop = {-2}; - - v1.SetLocalProperty(&prop, 1); - EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear()); - v1.SetLocalProperty(&prop, -2); - EXPECT_EQ(PropertyChangeInfo(&prop, 1), o.PropertyChangeInfoAndClear()); - v1.SetLocalProperty(&prop, 3); - EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear()); - v1.ClearLocalProperty(&prop); - EXPECT_EQ(PropertyChangeInfo(&prop, 3), o.PropertyChangeInfoAndClear()); - - // Sanity check to see if |PropertyChangeInfoAndClear| really clears. - EXPECT_EQ(PropertyChangeInfo(reinterpret_cast<const void*>(NULL), -3), - o.PropertyChangeInfoAndClear()); -} - -} // namespace mus diff --git a/components/mus/public/cpp/tests/view_manager_test_base.cc b/components/mus/public/cpp/tests/window_server_test_base.cc index e4bf2ba..649fc24 100644 --- a/components/mus/public/cpp/tests/view_manager_test_base.cc +++ b/components/mus/public/cpp/tests/window_server_test_base.cc @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/mus/public/cpp/tests/view_manager_test_base.h" +#include "components/mus/public/cpp/tests/window_server_test_base.h" #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/test/test_timeouts.h" -#include "components/mus/public/cpp/view.h" -#include "components/mus/public/cpp/view_tree_connection.h" -#include "components/mus/public/cpp/view_tree_host_factory.h" +#include "components/mus/public/cpp/window.h" +#include "components/mus/public/cpp/window_tree_connection.h" +#include "components/mus/public/cpp/window_tree_host_factory.h" #include "mojo/application/public/cpp/application_impl.h" namespace mus { @@ -26,15 +26,15 @@ void TimeoutRunLoop(const base::Closure& timeout_task, bool* timeout) { } // namespace -ViewManagerTestBase::ViewManagerTestBase() +WindowServerTestBase::WindowServerTestBase() : most_recent_connection_(nullptr), window_manager_(nullptr), - view_tree_connection_destroyed_(false) {} + window_tree_connection_destroyed_(false) {} -ViewManagerTestBase::~ViewManagerTestBase() {} +WindowServerTestBase::~WindowServerTestBase() {} // static -bool ViewManagerTestBase::DoRunLoopWithTimeout() { +bool WindowServerTestBase::DoRunLoopWithTimeout() { if (current_run_loop != nullptr) return false; @@ -51,7 +51,7 @@ bool ViewManagerTestBase::DoRunLoopWithTimeout() { } // static -bool ViewManagerTestBase::QuitRunLoop() { +bool WindowServerTestBase::QuitRunLoop() { if (!current_run_loop) return false; @@ -60,44 +60,44 @@ bool ViewManagerTestBase::QuitRunLoop() { return true; } -void ViewManagerTestBase::SetUp() { +void WindowServerTestBase::SetUp() { ApplicationTestBase::SetUp(); - CreateSingleViewTreeHost(application_impl(), this, &host_); + CreateSingleWindowTreeHost(application_impl(), this, &host_); ASSERT_TRUE(DoRunLoopWithTimeout()); // RunLoop should be quit by OnEmbed(). std::swap(window_manager_, most_recent_connection_); } -void ViewManagerTestBase::TearDown() { +void WindowServerTestBase::TearDown() { ApplicationTestBase::TearDown(); } -mojo::ApplicationDelegate* ViewManagerTestBase::GetApplicationDelegate() { +mojo::ApplicationDelegate* WindowServerTestBase::GetApplicationDelegate() { return this; } -bool ViewManagerTestBase::ConfigureIncomingConnection( +bool WindowServerTestBase::ConfigureIncomingConnection( mojo::ApplicationConnection* connection) { connection->AddService<mojo::ViewTreeClient>(this); return true; } -void ViewManagerTestBase::OnEmbed(View* root) { +void WindowServerTestBase::OnEmbed(Window* root) { most_recent_connection_ = root->connection(); EXPECT_TRUE(QuitRunLoop()); } -void ViewManagerTestBase::OnConnectionLost(ViewTreeConnection* connection) { - view_tree_connection_destroyed_ = true; +void WindowServerTestBase::OnConnectionLost(WindowTreeConnection* connection) { + window_tree_connection_destroyed_ = true; } -void ViewManagerTestBase::Create( +void WindowServerTestBase::Create( mojo::ApplicationConnection* connection, mojo::InterfaceRequest<mojo::ViewTreeClient> request) { - ViewTreeConnection::Create( + WindowTreeConnection::Create( this, request.Pass(), - ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED); + WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED); } } // namespace mus diff --git a/components/mus/public/cpp/tests/view_manager_test_base.h b/components/mus/public/cpp/tests/window_server_test_base.h index a1529f3..b46c871 100644 --- a/components/mus/public/cpp/tests/view_manager_test_base.h +++ b/components/mus/public/cpp/tests/window_server_test_base.h @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_BASE_H_ -#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_BASE_H_ +#ifndef COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_BASE_H_ +#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_BASE_H_ #include "base/memory/scoped_ptr.h" -#include "components/mus/public/cpp/view_tree_delegate.h" +#include "components/mus/public/cpp/window_tree_delegate.h" #include "components/mus/public/interfaces/view_tree.mojom.h" #include "components/mus/public/interfaces/view_tree_host.mojom.h" #include "mojo/application/public/cpp/application_delegate.h" @@ -15,22 +15,22 @@ namespace mus { -// ViewManagerTestBase is a base class for use with app tests that use -// ViewManager. SetUp() connects to the ViewManager and blocks until OnEmbed() -// has been invoked. window_manager() can be used to access the ViewManager +// WindowServerTestBase is a base class for use with app tests that use +// WindowServer. SetUp() connects to the WindowServer and blocks until OnEmbed() +// has been invoked. window_manager() can be used to access the WindowServer // established as part of SetUp(). -class ViewManagerTestBase +class WindowServerTestBase : public mojo::test::ApplicationTestBase, public mojo::ApplicationDelegate, - public ViewTreeDelegate, + public WindowTreeDelegate, public mojo::InterfaceFactory<mojo::ViewTreeClient> { public: - ViewManagerTestBase(); - ~ViewManagerTestBase() override; + WindowServerTestBase(); + ~WindowServerTestBase() override; - // True if ViewTreeDelegate::OnConnectionLost() was called. - bool view_tree_connection_destroyed() const { - return view_tree_connection_destroyed_; + // True if WindowTreeDelegate::OnConnectionLost() was called. + bool window_tree_connection_destroyed() const { + return window_tree_connection_destroyed_; } // Runs the MessageLoop until QuitRunLoop() is called, or a timeout occurs. @@ -42,10 +42,10 @@ class ViewManagerTestBase // success, false if a RunLoop isn't running. static bool QuitRunLoop() WARN_UNUSED_RESULT; - ViewTreeConnection* window_manager() { return window_manager_; } + WindowTreeConnection* window_manager() { return window_manager_; } protected: - ViewTreeConnection* most_recent_connection() { + WindowTreeConnection* most_recent_connection() { return most_recent_connection_; } @@ -60,9 +60,9 @@ class ViewManagerTestBase bool ConfigureIncomingConnection( mojo::ApplicationConnection* connection) override; - // ViewTreeDelegate: - void OnEmbed(View* root) override; - void OnConnectionLost(ViewTreeConnection* connection) override; + // WindowTreeDelegate: + void OnEmbed(Window* root) override; + void OnConnectionLost(WindowTreeConnection* connection) override; // InterfaceFactory<ViewTreeClient>: void Create(mojo::ApplicationConnection* connection, @@ -70,20 +70,20 @@ class ViewManagerTestBase // Used to receive the most recent view tree connection loaded by an embed // action. - ViewTreeConnection* most_recent_connection_; + WindowTreeConnection* most_recent_connection_; private: mojo::ViewTreeHostPtr host_; // The View Manager connection held by the window manager (app running at the // root view). - ViewTreeConnection* window_manager_; + WindowTreeConnection* window_manager_; - bool view_tree_connection_destroyed_; + bool window_tree_connection_destroyed_; - MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTestBase); + MOJO_DISALLOW_COPY_AND_ASSIGN(WindowServerTestBase); }; } // namespace mus -#endif // COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_BASE_H_ +#endif // COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_BASE_H_ diff --git a/components/mus/public/cpp/tests/view_manager_test_suite.cc b/components/mus/public/cpp/tests/window_server_test_suite.cc index a1e0c98..ea1a04c 100644 --- a/components/mus/public/cpp/tests/view_manager_test_suite.cc +++ b/components/mus/public/cpp/tests/window_server_test_suite.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/mus/public/cpp/tests/view_manager_test_suite.h" +#include "components/mus/public/cpp/tests/window_server_test_suite.h" #include "base/i18n/icu_util.h" @@ -12,12 +12,12 @@ namespace mus { -ViewManagerTestSuite::ViewManagerTestSuite(int argc, char** argv) +WindowServerTestSuite::WindowServerTestSuite(int argc, char** argv) : TestSuite(argc, argv) {} -ViewManagerTestSuite::~ViewManagerTestSuite() {} +WindowServerTestSuite::~WindowServerTestSuite() {} -void ViewManagerTestSuite::Initialize() { +void WindowServerTestSuite::Initialize() { #if defined(USE_X11) // Each test ends up creating a new thread for the native viewport service. // In other words we'll use X on different threads, so tell it that. diff --git a/components/mus/public/cpp/tests/window_server_test_suite.h b/components/mus/public/cpp/tests/window_server_test_suite.h new file mode 100644 index 0000000..cbc2eb7 --- /dev/null +++ b/components/mus/public/cpp/tests/window_server_test_suite.h @@ -0,0 +1,27 @@ +// 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. + +#ifndef COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_SUITE_H_ +#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_SUITE_H_ + +#include "base/test/test_suite.h" +#include "third_party/mojo/src/mojo/public/cpp/system/macros.h" + +namespace mus { + +class WindowServerTestSuite : public base::TestSuite { + public: + WindowServerTestSuite(int argc, char** argv); + ~WindowServerTestSuite() override; + + protected: + void Initialize() override; + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(WindowServerTestSuite); +}; + +} // namespace mus + +#endif // COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_SUITE_H_ diff --git a/components/mus/public/cpp/tests/window_unittest.cc b/components/mus/public/cpp/tests/window_unittest.cc new file mode 100644 index 0000000..870a026 --- /dev/null +++ b/components/mus/public/cpp/tests/window_unittest.cc @@ -0,0 +1,875 @@ +// 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 "components/mus/public/cpp/window.h" + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "components/mus/public/cpp/lib/window_private.h" +#include "components/mus/public/cpp/util.h" +#include "components/mus/public/cpp/window_observer.h" +#include "components/mus/public/cpp/window_property.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mus { + +// Window --------------------------------------------------------------------- + +typedef testing::Test WindowTest; + +// Subclass with public ctor/dtor. +class TestWindow : public Window { + public: + TestWindow() { WindowPrivate(this).set_id(1); } + ~TestWindow() {} + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(TestWindow); +}; + +TEST_F(WindowTest, AddChild) { + TestWindow w1; + TestWindow w11; + w1.AddChild(&w11); + EXPECT_EQ(1U, w1.children().size()); +} + +TEST_F(WindowTest, RemoveChild) { + TestWindow w1; + TestWindow w11; + w1.AddChild(&w11); + EXPECT_EQ(1U, w1.children().size()); + w1.RemoveChild(&w11); + EXPECT_EQ(0U, w1.children().size()); +} + +TEST_F(WindowTest, Reparent) { + TestWindow w1; + TestWindow w2; + TestWindow w11; + w1.AddChild(&w11); + EXPECT_EQ(1U, w1.children().size()); + w2.AddChild(&w11); + EXPECT_EQ(1U, w2.children().size()); + EXPECT_EQ(0U, w1.children().size()); +} + +TEST_F(WindowTest, Contains) { + TestWindow w1; + + // Direct descendant. + TestWindow w11; + w1.AddChild(&w11); + EXPECT_TRUE(w1.Contains(&w11)); + + // Indirect descendant. + TestWindow w111; + w11.AddChild(&w111); + EXPECT_TRUE(w1.Contains(&w111)); +} + +TEST_F(WindowTest, GetChildById) { + TestWindow w1; + WindowPrivate(&w1).set_id(1); + TestWindow w11; + WindowPrivate(&w11).set_id(11); + w1.AddChild(&w11); + TestWindow w111; + WindowPrivate(&w111).set_id(111); + w11.AddChild(&w111); + + // Find direct & indirect descendents. + EXPECT_EQ(&w11, w1.GetChildById(w11.id())); + EXPECT_EQ(&w111, w1.GetChildById(w111.id())); +} + +TEST_F(WindowTest, DrawnAndVisible) { + TestWindow w1; + EXPECT_TRUE(w1.visible()); + EXPECT_FALSE(w1.IsDrawn()); + + WindowPrivate(&w1).set_drawn(true); + + TestWindow w11; + w1.AddChild(&w11); + EXPECT_TRUE(w11.visible()); + EXPECT_TRUE(w11.IsDrawn()); + + w1.RemoveChild(&w11); + EXPECT_TRUE(w11.visible()); + EXPECT_FALSE(w11.IsDrawn()); +} + +namespace { +DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2); +DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish"); +} + +TEST_F(WindowTest, Property) { + TestWindow w; + + // Non-existent properties should return the default walues. + EXPECT_EQ(-2, w.GetLocalProperty(kIntKey)); + EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey)); + + // A set property walue should be returned again (even if it's the default + // walue). + w.SetLocalProperty(kIntKey, INT_MAX); + EXPECT_EQ(INT_MAX, w.GetLocalProperty(kIntKey)); + w.SetLocalProperty(kIntKey, -2); + EXPECT_EQ(-2, w.GetLocalProperty(kIntKey)); + w.SetLocalProperty(kIntKey, INT_MIN); + EXPECT_EQ(INT_MIN, w.GetLocalProperty(kIntKey)); + + w.SetLocalProperty(kStringKey, static_cast<const char*>(NULL)); + EXPECT_EQ(NULL, w.GetLocalProperty(kStringKey)); + w.SetLocalProperty(kStringKey, "squeamish"); + EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey)); + w.SetLocalProperty(kStringKey, "ossifrage"); + EXPECT_EQ(std::string("ossifrage"), w.GetLocalProperty(kStringKey)); + + // ClearProperty should restore the default walue. + w.ClearLocalProperty(kIntKey); + EXPECT_EQ(-2, w.GetLocalProperty(kIntKey)); + w.ClearLocalProperty(kStringKey); + EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey)); +} + +namespace { + +class TestProperty { + public: + TestProperty() {} + virtual ~TestProperty() { last_deleted_ = this; } + static TestProperty* last_deleted() { return last_deleted_; } + + private: + static TestProperty* last_deleted_; + MOJO_DISALLOW_COPY_AND_ASSIGN(TestProperty); +}; + +TestProperty* TestProperty::last_deleted_ = NULL; + +DEFINE_OWNED_WINDOW_PROPERTY_KEY(TestProperty, kOwnedKey, NULL); + +} // namespace + +TEST_F(WindowTest, OwnedProperty) { + TestProperty* p3 = NULL; + { + TestWindow w; + EXPECT_EQ(NULL, w.GetLocalProperty(kOwnedKey)); + TestProperty* p1 = new TestProperty(); + w.SetLocalProperty(kOwnedKey, p1); + EXPECT_EQ(p1, w.GetLocalProperty(kOwnedKey)); + EXPECT_EQ(NULL, TestProperty::last_deleted()); + + TestProperty* p2 = new TestProperty(); + w.SetLocalProperty(kOwnedKey, p2); + EXPECT_EQ(p2, w.GetLocalProperty(kOwnedKey)); + EXPECT_EQ(p1, TestProperty::last_deleted()); + + w.ClearLocalProperty(kOwnedKey); + EXPECT_EQ(NULL, w.GetLocalProperty(kOwnedKey)); + EXPECT_EQ(p2, TestProperty::last_deleted()); + + p3 = new TestProperty(); + w.SetLocalProperty(kOwnedKey, p3); + EXPECT_EQ(p3, w.GetLocalProperty(kOwnedKey)); + EXPECT_EQ(p2, TestProperty::last_deleted()); + } + + EXPECT_EQ(p3, TestProperty::last_deleted()); +} + +// WindowObserver -------------------------------------------------------- + +typedef testing::Test WindowObserverTest; + +bool TreeChangeParamsMatch(const WindowObserver::TreeChangeParams& lhs, + const WindowObserver::TreeChangeParams& rhs) { + return lhs.target == rhs.target && lhs.old_parent == rhs.old_parent && + lhs.new_parent == rhs.new_parent && lhs.receiver == rhs.receiver; +} + +class TreeChangeObserver : public WindowObserver { + public: + explicit TreeChangeObserver(Window* observee) : observee_(observee) { + observee_->AddObserver(this); + } + ~TreeChangeObserver() override { observee_->RemoveObserver(this); } + + void Reset() { received_params_.clear(); } + + const std::vector<TreeChangeParams>& received_params() { + return received_params_; + } + + private: + // Overridden from WindowObserver: + void OnTreeChanging(const TreeChangeParams& params) override { + received_params_.push_back(params); + } + void OnTreeChanged(const TreeChangeParams& params) override { + received_params_.push_back(params); + } + + Window* observee_; + std::vector<TreeChangeParams> received_params_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver); +}; + +// Adds/Removes w11 to w1. +TEST_F(WindowObserverTest, TreeChange_SimpleAddRemove) { + TestWindow w1; + TreeChangeObserver o1(&w1); + EXPECT_TRUE(o1.received_params().empty()); + + TestWindow w11; + TreeChangeObserver o11(&w11); + EXPECT_TRUE(o11.received_params().empty()); + + // Add. + + w1.AddChild(&w11); + + EXPECT_EQ(2U, o1.received_params().size()); + WindowObserver::TreeChangeParams p1; + p1.target = &w11; + p1.receiver = &w1; + p1.old_parent = NULL; + p1.new_parent = &w1; + EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); + + EXPECT_EQ(2U, o11.received_params().size()); + WindowObserver::TreeChangeParams p11 = p1; + p11.receiver = &w11; + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); + + o1.Reset(); + o11.Reset(); + EXPECT_TRUE(o1.received_params().empty()); + EXPECT_TRUE(o11.received_params().empty()); + + // Remove. + + w1.RemoveChild(&w11); + + EXPECT_EQ(2U, o1.received_params().size()); + p1.target = &w11; + p1.receiver = &w1; + p1.old_parent = &w1; + p1.new_parent = NULL; + EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); + + EXPECT_EQ(2U, o11.received_params().size()); + p11 = p1; + p11.receiver = &w11; + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); +} + +// Creates these two trees: +// w1 +// +- w11 +// w111 +// +- w1111 +// +- w1112 +// Then adds/removes w111 from w11. +TEST_F(WindowObserverTest, TreeChange_NestedAddRemove) { + TestWindow w1, w11, w111, w1111, w1112; + + // Root tree. + w1.AddChild(&w11); + + // Tree to be attached. + w111.AddChild(&w1111); + w111.AddChild(&w1112); + + TreeChangeObserver o1(&w1), o11(&w11), o111(&w111), o1111(&w1111), + o1112(&w1112); + WindowObserver::TreeChangeParams p1, p11, p111, p1111, p1112; + + // Add. + + w11.AddChild(&w111); + + EXPECT_EQ(2U, o1.received_params().size()); + p1.target = &w111; + p1.receiver = &w1; + p1.old_parent = NULL; + p1.new_parent = &w11; + EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); + + EXPECT_EQ(2U, o11.received_params().size()); + p11 = p1; + p11.receiver = &w11; + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back())); + + EXPECT_EQ(2U, o111.received_params().size()); + p111 = p11; + p111.receiver = &w111; + EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); + + EXPECT_EQ(2U, o1111.received_params().size()); + p1111 = p111; + p1111.receiver = &w1111; + EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back())); + + EXPECT_EQ(2U, o1112.received_params().size()); + p1112 = p111; + p1112.receiver = &w1112; + EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back())); + + // Remove. + o1.Reset(); + o11.Reset(); + o111.Reset(); + o1111.Reset(); + o1112.Reset(); + EXPECT_TRUE(o1.received_params().empty()); + EXPECT_TRUE(o11.received_params().empty()); + EXPECT_TRUE(o111.received_params().empty()); + EXPECT_TRUE(o1111.received_params().empty()); + EXPECT_TRUE(o1112.received_params().empty()); + + w11.RemoveChild(&w111); + + EXPECT_EQ(2U, o1.received_params().size()); + p1.target = &w111; + p1.receiver = &w1; + p1.old_parent = &w11; + p1.new_parent = NULL; + EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); + + EXPECT_EQ(2U, o11.received_params().size()); + p11 = p1; + p11.receiver = &w11; + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); + + EXPECT_EQ(2U, o111.received_params().size()); + p111 = p11; + p111.receiver = &w111; + EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); + + EXPECT_EQ(2U, o1111.received_params().size()); + p1111 = p111; + p1111.receiver = &w1111; + EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back())); + + EXPECT_EQ(2U, o1112.received_params().size()); + p1112 = p111; + p1112.receiver = &w1112; + EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back())); +} + +TEST_F(WindowObserverTest, TreeChange_Reparent) { + TestWindow w1, w11, w12, w111; + w1.AddChild(&w11); + w1.AddChild(&w12); + w11.AddChild(&w111); + + TreeChangeObserver o1(&w1), o11(&w11), o12(&w12), o111(&w111); + + // Reparent. + w12.AddChild(&w111); + + // w1 (root) should see both changing and changed notifications. + EXPECT_EQ(4U, o1.received_params().size()); + WindowObserver::TreeChangeParams p1; + p1.target = &w111; + p1.receiver = &w1; + p1.old_parent = &w11; + p1.new_parent = &w12; + EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back())); + + // w11 should see changing notifications. + EXPECT_EQ(2U, o11.received_params().size()); + WindowObserver::TreeChangeParams p11; + p11 = p1; + p11.receiver = &w11; + EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front())); + + // w12 should see changed notifications. + EXPECT_EQ(2U, o12.received_params().size()); + WindowObserver::TreeChangeParams p12; + p12 = p1; + p12.receiver = &w12; + EXPECT_TRUE(TreeChangeParamsMatch(p12, o12.received_params().back())); + + // w111 should see both changing and changed notifications. + EXPECT_EQ(2U, o111.received_params().size()); + WindowObserver::TreeChangeParams p111; + p111 = p1; + p111.receiver = &w111; + EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front())); + EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back())); +} + +namespace { + +class OrderChangeObserver : public WindowObserver { + public: + struct Change { + Window* window; + Window* relative_window; + mojo::OrderDirection direction; + }; + typedef std::vector<Change> Changes; + + explicit OrderChangeObserver(Window* observee) : observee_(observee) { + observee_->AddObserver(this); + } + ~OrderChangeObserver() override { observee_->RemoveObserver(this); } + + Changes GetAndClearChanges() { + Changes changes; + changes_.swap(changes); + return changes; + } + + private: + // Overridden from WindowObserver: + void OnWindowReordering(Window* window, + Window* relative_window, + mojo::OrderDirection direction) override { + OnWindowReordered(window, relative_window, direction); + } + + void OnWindowReordered(Window* window, + Window* relative_window, + mojo::OrderDirection direction) override { + Change change; + change.window = window; + change.relative_window = relative_window; + change.direction = direction; + changes_.push_back(change); + } + + Window* observee_; + Changes changes_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); +}; + +} // namespace + +TEST_F(WindowObserverTest, Order) { + TestWindow w1, w11, w12, w13; + w1.AddChild(&w11); + w1.AddChild(&w12); + w1.AddChild(&w13); + + // Order: w11, w12, w13 + EXPECT_EQ(3U, w1.children().size()); + EXPECT_EQ(&w11, w1.children().front()); + EXPECT_EQ(&w13, w1.children().back()); + + { + OrderChangeObserver observer(&w11); + + // Move w11 to front. + // Resulting order: w12, w13, w11 + w11.MoveToFront(); + EXPECT_EQ(&w12, w1.children().front()); + EXPECT_EQ(&w11, w1.children().back()); + + OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(2U, changes.size()); + EXPECT_EQ(&w11, changes[0].window); + EXPECT_EQ(&w13, changes[0].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction); + + EXPECT_EQ(&w11, changes[1].window); + EXPECT_EQ(&w13, changes[1].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction); + } + + { + OrderChangeObserver observer(&w11); + + // Move w11 to back. + // Resulting order: w11, w12, w13 + w11.MoveToBack(); + EXPECT_EQ(&w11, w1.children().front()); + EXPECT_EQ(&w13, w1.children().back()); + + OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(2U, changes.size()); + EXPECT_EQ(&w11, changes[0].window); + EXPECT_EQ(&w12, changes[0].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction); + + EXPECT_EQ(&w11, changes[1].window); + EXPECT_EQ(&w12, changes[1].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction); + } + + { + OrderChangeObserver observer(&w11); + + // Move w11 above w12. + // Resulting order: w12. w11, w13 + w11.Reorder(&w12, mojo::ORDER_DIRECTION_ABOVE); + EXPECT_EQ(&w12, w1.children().front()); + EXPECT_EQ(&w13, w1.children().back()); + + OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(2U, changes.size()); + EXPECT_EQ(&w11, changes[0].window); + EXPECT_EQ(&w12, changes[0].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction); + + EXPECT_EQ(&w11, changes[1].window); + EXPECT_EQ(&w12, changes[1].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction); + } + + { + OrderChangeObserver observer(&w11); + + // Move w11 below w12. + // Resulting order: w11, w12, w13 + w11.Reorder(&w12, mojo::ORDER_DIRECTION_BELOW); + EXPECT_EQ(&w11, w1.children().front()); + EXPECT_EQ(&w13, w1.children().back()); + + OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(2U, changes.size()); + EXPECT_EQ(&w11, changes[0].window); + EXPECT_EQ(&w12, changes[0].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction); + + EXPECT_EQ(&w11, changes[1].window); + EXPECT_EQ(&w12, changes[1].relative_window); + EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction); + } +} + +namespace { + +typedef std::vector<std::string> Changes; + +std::string WindowIdToString(Id id) { + return (id == 0) ? "null" + : base::StringPrintf("%d,%d", HiWord(id), LoWord(id)); +} + +std::string RectToString(const mojo::Rect& rect) { + return base::StringPrintf("%d,%d %dx%d", rect.x, rect.y, rect.width, + rect.height); +} + +class BoundsChangeObserver : public WindowObserver { + public: + explicit BoundsChangeObserver(Window* window) : window_(window) { + window_->AddObserver(this); + } + ~BoundsChangeObserver() override { window_->RemoveObserver(this); } + + Changes GetAndClearChanges() { + Changes changes; + changes.swap(changes_); + return changes; + } + + private: + // Overridden from WindowObserver: + void OnWindowBoundsChanging(Window* window, + const mojo::Rect& old_bounds, + const mojo::Rect& new_bounds) override { + changes_.push_back(base::StringPrintf( + "window=%s old_bounds=%s new_bounds=%s phase=changing", + WindowIdToString(window->id()).c_str(), + RectToString(old_bounds).c_str(), RectToString(new_bounds).c_str())); + } + void OnWindowBoundsChanged(Window* window, + const mojo::Rect& old_bounds, + const mojo::Rect& new_bounds) override { + changes_.push_back(base::StringPrintf( + "window=%s old_bounds=%s new_bounds=%s phase=changed", + WindowIdToString(window->id()).c_str(), + RectToString(old_bounds).c_str(), RectToString(new_bounds).c_str())); + } + + Window* window_; + Changes changes_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); +}; + +} // namespace + +TEST_F(WindowObserverTest, SetBounds) { + TestWindow w1; + { + BoundsChangeObserver observer(&w1); + mojo::Rect rect; + rect.width = rect.height = 100; + w1.SetBounds(rect); + + Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(2U, changes.size()); + EXPECT_EQ( + "window=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changing", + changes[0]); + EXPECT_EQ( + "window=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changed", + changes[1]); + } +} + +namespace { + +class VisibilityChangeObserver : public WindowObserver { + public: + explicit VisibilityChangeObserver(Window* window) : window_(window) { + window_->AddObserver(this); + } + ~VisibilityChangeObserver() override { window_->RemoveObserver(this); } + + Changes GetAndClearChanges() { + Changes changes; + changes.swap(changes_); + return changes; + } + + private: + // Overridden from WindowObserver: + void OnWindowVisibilityChanging(Window* window) override { + changes_.push_back( + base::StringPrintf("window=%s phase=changing wisibility=%s", + WindowIdToString(window->id()).c_str(), + window->visible() ? "true" : "false")); + } + void OnWindowVisibilityChanged(Window* window) override { + changes_.push_back( + base::StringPrintf("window=%s phase=changed wisibility=%s", + WindowIdToString(window->id()).c_str(), + window->visible() ? "true" : "false")); + } + + Window* window_; + Changes changes_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); +}; + +} // namespace + +TEST_F(WindowObserverTest, SetVisible) { + TestWindow w1; + EXPECT_TRUE(w1.visible()); + { + // Change wisibility from true to false and make sure we get notifications. + VisibilityChangeObserver observer(&w1); + w1.SetVisible(false); + + Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(2U, changes.size()); + EXPECT_EQ("window=0,1 phase=changing wisibility=true", changes[0]); + EXPECT_EQ("window=0,1 phase=changed wisibility=false", changes[1]); + } + { + // Set visible to existing walue and werify no notifications. + VisibilityChangeObserver observer(&w1); + w1.SetVisible(false); + EXPECT_TRUE(observer.GetAndClearChanges().empty()); + } +} + +TEST_F(WindowObserverTest, SetVisibleParent) { + TestWindow parent; + WindowPrivate(&parent).set_id(1); + TestWindow child; + WindowPrivate(&child).set_id(2); + parent.AddChild(&child); + EXPECT_TRUE(parent.visible()); + EXPECT_TRUE(child.visible()); + { + // Change wisibility from true to false and make sure we get notifications + // on the parent. + VisibilityChangeObserver observer(&parent); + child.SetVisible(false); + + Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(1U, changes.size()); + EXPECT_EQ("window=0,2 phase=changed wisibility=false", changes[0]); + } +} + +TEST_F(WindowObserverTest, SetVisibleChild) { + TestWindow parent; + WindowPrivate(&parent).set_id(1); + TestWindow child; + WindowPrivate(&child).set_id(2); + parent.AddChild(&child); + EXPECT_TRUE(parent.visible()); + EXPECT_TRUE(child.visible()); + { + // Change wisibility from true to false and make sure we get notifications + // on the child. + VisibilityChangeObserver observer(&child); + parent.SetVisible(false); + + Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(1U, changes.size()); + EXPECT_EQ("window=0,1 phase=changed wisibility=false", changes[0]); + } +} + +namespace { + +class SharedPropertyChangeObserver : public WindowObserver { + public: + explicit SharedPropertyChangeObserver(Window* window) : window_(window) { + window_->AddObserver(this); + } + ~SharedPropertyChangeObserver() override { window_->RemoveObserver(this); } + + Changes GetAndClearChanges() { + Changes changes; + changes.swap(changes_); + return changes; + } + + private: + // Overridden from WindowObserver: + void OnWindowSharedPropertyChanged( + Window* window, + const std::string& name, + const std::vector<uint8_t>* old_data, + const std::vector<uint8_t>* new_data) override { + changes_.push_back(base::StringPrintf( + "window=%s shared property changed key=%s old_value=%s new_value=%s", + WindowIdToString(window->id()).c_str(), name.c_str(), + VectorToString(old_data).c_str(), VectorToString(new_data).c_str())); + } + + std::string VectorToString(const std::vector<uint8_t>* data) { + if (!data) + return "NULL"; + std::string s; + for (char c : *data) + s += c; + return s; + } + + Window* window_; + Changes changes_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver); +}; + +} // namespace + +TEST_F(WindowObserverTest, SetLocalProperty) { + TestWindow w1; + std::vector<uint8_t> one(1, '1'); + + { + // Change wisibility from true to false and make sure we get notifications. + SharedPropertyChangeObserver observer(&w1); + w1.SetSharedProperty("one", &one); + Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(1U, changes.size()); + EXPECT_EQ( + "window=0,1 shared property changed key=one old_value=NULL new_value=1", + changes[0]); + EXPECT_EQ(1U, w1.shared_properties().size()); + } + { + // Set visible to existing walue and werify no notifications. + SharedPropertyChangeObserver observer(&w1); + w1.SetSharedProperty("one", &one); + EXPECT_TRUE(observer.GetAndClearChanges().empty()); + EXPECT_EQ(1U, w1.shared_properties().size()); + } + { + // Set the walue to NULL to delete it. + // Change wisibility from true to false and make sure we get notifications. + SharedPropertyChangeObserver observer(&w1); + w1.SetSharedProperty("one", NULL); + Changes changes = observer.GetAndClearChanges(); + ASSERT_EQ(1U, changes.size()); + EXPECT_EQ( + "window=0,1 shared property changed key=one old_value=1 new_value=NULL", + changes[0]); + EXPECT_EQ(0U, w1.shared_properties().size()); + } + { + // Setting a null property to null shouldn't update us. + SharedPropertyChangeObserver observer(&w1); + w1.SetSharedProperty("one", NULL); + EXPECT_TRUE(observer.GetAndClearChanges().empty()); + EXPECT_EQ(0U, w1.shared_properties().size()); + } +} + +namespace { + +typedef std::pair<const void*, intptr_t> PropertyChangeInfo; + +class LocalPropertyChangeObserver : public WindowObserver { + public: + explicit LocalPropertyChangeObserver(Window* window) + : window_(window), property_key_(nullptr), old_property_value_(-1) { + window_->AddObserver(this); + } + ~LocalPropertyChangeObserver() override { window_->RemoveObserver(this); } + + PropertyChangeInfo PropertyChangeInfoAndClear() { + PropertyChangeInfo result(property_key_, old_property_value_); + property_key_ = NULL; + old_property_value_ = -3; + return result; + } + + private: + void OnWindowLocalPropertyChanged(Window* window, + const void* key, + intptr_t old) override { + property_key_ = key; + old_property_value_ = old; + } + + Window* window_; + const void* property_key_; + intptr_t old_property_value_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver); +}; + +} // namespace + +TEST_F(WindowObserverTest, LocalPropertyChanged) { + TestWindow w1; + LocalPropertyChangeObserver o(&w1); + + static const WindowProperty<int> prop = {-2}; + + w1.SetLocalProperty(&prop, 1); + EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear()); + w1.SetLocalProperty(&prop, -2); + EXPECT_EQ(PropertyChangeInfo(&prop, 1), o.PropertyChangeInfoAndClear()); + w1.SetLocalProperty(&prop, 3); + EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear()); + w1.ClearLocalProperty(&prop); + EXPECT_EQ(PropertyChangeInfo(&prop, 3), o.PropertyChangeInfoAndClear()); + + // Sanity check to see if |PropertyChangeInfoAndClear| really clears. + EXPECT_EQ(PropertyChangeInfo(reinterpret_cast<const void*>(NULL), -3), + o.PropertyChangeInfoAndClear()); +} + +} // namespace mus |