Index: mojo/services/public/cpp/view_manager/tests/view_unittest.cc |
diff --git a/mojo/services/public/cpp/view_manager/tests/view_unittest.cc b/mojo/services/public/cpp/view_manager/tests/view_unittest.cc |
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c63089eeddd38915d0e7b47b1ded4b4de58ab61b 100644 |
--- a/mojo/services/public/cpp/view_manager/tests/view_unittest.cc |
+++ b/mojo/services/public/cpp/view_manager/tests/view_unittest.cc |
@@ -0,0 +1,544 @@ |
+// 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 "mojo/services/public/cpp/view_manager/view.h" |
+ |
+#include "base/logging.h" |
+#include "base/strings/stringprintf.h" |
+#include "mojo/services/public/cpp/view_manager/lib/view_private.h" |
+#include "mojo/services/public/cpp/view_manager/util.h" |
+#include "mojo/services/public/cpp/view_manager/view_observer.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace mojo { |
+ |
+// View ------------------------------------------------------------------------ |
+ |
+typedef testing::Test ViewTest; |
+ |
+// Subclass with public ctor/dtor. |
+class TestView : public View { |
+ public: |
+ TestView() { |
+ ViewPrivate(this).set_id(1); |
+ } |
+ ~TestView() {} |
+ |
+ private: |
+ 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())); |
+} |
+ |
+// 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); |
+ } |
+ virtual ~TreeChangeObserver() { |
+ observee_->RemoveObserver(this); |
+ } |
+ |
+ void Reset() { |
+ received_params_.clear(); |
+ } |
+ |
+ const std::vector<TreeChangeParams>& received_params() { |
+ return received_params_; |
+ } |
+ |
+ private: |
+ // Overridden from ViewObserver: |
+ virtual void OnTreeChanging(const TreeChangeParams& params) OVERRIDE { |
+ received_params_.push_back(params); |
+ } |
+ virtual void OnTreeChanged(const TreeChangeParams& params) OVERRIDE { |
+ received_params_.push_back(params); |
+ } |
+ |
+ View* observee_; |
+ std::vector<TreeChangeParams> received_params_; |
+ |
+ 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; |
+ OrderDirection direction; |
+ }; |
+ typedef std::vector<Change> Changes; |
+ |
+ explicit OrderChangeObserver(View* observee) : observee_(observee) { |
+ observee_->AddObserver(this); |
+ } |
+ virtual ~OrderChangeObserver() { |
+ observee_->RemoveObserver(this); |
+ } |
+ |
+ Changes GetAndClearChanges() { |
+ Changes changes; |
+ changes_.swap(changes); |
+ return changes; |
+ } |
+ |
+ private: |
+ // Overridden from ViewObserver: |
+ virtual void OnViewReordering(View* view, |
+ View* relative_view, |
+ OrderDirection direction) OVERRIDE { |
+ OnViewReordered(view, relative_view, direction); |
+ } |
+ |
+ virtual void OnViewReordered(View* view, |
+ View* relative_view, |
+ OrderDirection direction) OVERRIDE { |
+ Change change; |
+ change.view = view; |
+ change.relative_view = relative_view; |
+ change.direction = direction; |
+ changes_.push_back(change); |
+ } |
+ |
+ View* observee_; |
+ Changes changes_; |
+ |
+ 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(); |
+ EXPECT_EQ(2U, changes.size()); |
+ EXPECT_EQ(&v11, changes[0].view); |
+ EXPECT_EQ(&v13, changes[0].relative_view); |
+ EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[0].direction); |
+ |
+ EXPECT_EQ(&v11, changes[1].view); |
+ EXPECT_EQ(&v13, changes[1].relative_view); |
+ EXPECT_EQ(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(); |
+ EXPECT_EQ(2U, changes.size()); |
+ EXPECT_EQ(&v11, changes[0].view); |
+ EXPECT_EQ(&v12, changes[0].relative_view); |
+ EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[0].direction); |
+ |
+ EXPECT_EQ(&v11, changes[1].view); |
+ EXPECT_EQ(&v12, changes[1].relative_view); |
+ EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[1].direction); |
+ } |
+ |
+ { |
+ OrderChangeObserver observer(&v11); |
+ |
+ // Move v11 above v12. |
+ // Resulting order: v12. v11, v13 |
+ v11.Reorder(&v12, ORDER_DIRECTION_ABOVE); |
+ EXPECT_EQ(&v12, v1.children().front()); |
+ EXPECT_EQ(&v13, v1.children().back()); |
+ |
+ OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); |
+ EXPECT_EQ(2U, changes.size()); |
+ EXPECT_EQ(&v11, changes[0].view); |
+ EXPECT_EQ(&v12, changes[0].relative_view); |
+ EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[0].direction); |
+ |
+ EXPECT_EQ(&v11, changes[1].view); |
+ EXPECT_EQ(&v12, changes[1].relative_view); |
+ EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[1].direction); |
+ } |
+ |
+ { |
+ OrderChangeObserver observer(&v11); |
+ |
+ // Move v11 below v12. |
+ // Resulting order: v11, v12, v13 |
+ v11.Reorder(&v12, ORDER_DIRECTION_BELOW); |
+ EXPECT_EQ(&v11, v1.children().front()); |
+ EXPECT_EQ(&v13, v1.children().back()); |
+ |
+ OrderChangeObserver::Changes changes = observer.GetAndClearChanges(); |
+ EXPECT_EQ(2U, changes.size()); |
+ EXPECT_EQ(&v11, changes[0].view); |
+ EXPECT_EQ(&v12, changes[0].relative_view); |
+ EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[0].direction); |
+ |
+ EXPECT_EQ(&v11, changes[1].view); |
+ EXPECT_EQ(&v12, changes[1].relative_view); |
+ EXPECT_EQ(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 gfx::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); |
+ } |
+ virtual ~BoundsChangeObserver() { |
+ view_->RemoveObserver(this); |
+ } |
+ |
+ Changes GetAndClearChanges() { |
+ Changes changes; |
+ changes.swap(changes_); |
+ return changes; |
+ } |
+ |
+ private: |
+ // Overridden from ViewObserver: |
+ virtual void OnViewBoundsChanging(View* view, |
+ const gfx::Rect& old_bounds, |
+ const gfx::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())); |
+ } |
+ virtual void OnViewBoundsChanged(View* view, |
+ const gfx::Rect& old_bounds, |
+ const gfx::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_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(ViewObserverTest, SetBounds) { |
+ TestView v1; |
+ { |
+ BoundsChangeObserver observer(&v1); |
+ v1.SetBounds(gfx::Rect(0, 0, 100, 100)); |
+ |
+ Changes changes = observer.GetAndClearChanges(); |
+ EXPECT_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 mojo |