1 // Copyright 2014 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.
5 #include "mojo/services/public/cpp/view_manager/view_manager.h"
8 #include "base/logging.h"
9 #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h"
10 #include "mojo/services/public/cpp/view_manager/util.h"
11 #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h"
12 #include "mojo/shell/shell_test_helper.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 namespace view_manager {
19 base::RunLoop* current_run_loop = NULL;
22 base::RunLoop run_loop;
23 current_run_loop = &run_loop;
24 current_run_loop->Run();
25 current_run_loop = NULL;
29 current_run_loop->Quit();
32 // ViewManager -----------------------------------------------------------------
34 // These tests model synchronization of two peer connections to the view manager
35 // service, that are given access to some root node.
37 class ViewManagerTest : public testing::Test {
39 ViewManagerTest() : commit_count_(0) {}
42 ViewManager* view_manager_1() { return view_manager_1_.get(); }
43 ViewManager* view_manager_2() { return view_manager_2_.get(); }
45 ViewTreeNode* CreateNodeInParent(ViewTreeNode* parent) {
46 ViewManager* parent_manager = ViewTreeNodePrivate(parent).view_manager();
47 ViewTreeNode* node = ViewTreeNode::Create(parent_manager);
48 parent->AddChild(node);
52 void DestroyViewManager1() {
53 view_manager_1_.reset();
57 // Overridden from testing::Test:
58 virtual void SetUp() OVERRIDE {
60 view_manager_1_.reset(new ViewManager(test_helper_.shell()));
61 view_manager_2_.reset(new ViewManager(test_helper_.shell()));
62 view_manager_1_->Init();
63 view_manager_2_->Init();
66 base::MessageLoop loop_;
67 shell::ShellTestHelper test_helper_;
68 scoped_ptr<ViewManager> view_manager_1_;
69 scoped_ptr<ViewManager> view_manager_2_;
72 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
75 // Base class for helpers that quit the current runloop after a specific tree
76 // change is observed by a view manager.
77 class TreeObserverBase : public ViewTreeNodeObserver {
79 explicit TreeObserverBase(ViewManager* view_manager)
80 : view_manager_(view_manager) {
81 view_manager_->tree()->AddObserver(this);
83 virtual ~TreeObserverBase() {
84 view_manager_->tree()->RemoveObserver(this);
88 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) = 0;
90 ViewManager* view_manager() { return view_manager_; }
93 // Overridden from ViewTreeNodeObserver:
94 virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE {
95 if (ShouldQuitRunLoop(params))
99 ViewManager* view_manager_;
100 DISALLOW_COPY_AND_ASSIGN(TreeObserverBase);
103 // Spins a runloop until the tree beginning at |root| has |tree_size| nodes
104 // (including |root|).
105 class TreeSizeMatchesWaiter : public TreeObserverBase {
107 TreeSizeMatchesWaiter(ViewManager* view_manager, size_t tree_size)
108 : TreeObserverBase(view_manager),
109 tree_size_(tree_size) {
112 virtual ~TreeSizeMatchesWaiter() {}
115 // Overridden from TreeObserverBase:
116 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
117 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
119 return CountNodes(view_manager()->tree()) == tree_size_;
122 size_t CountNodes(ViewTreeNode* node) const {
124 ViewTreeNode::Children::const_iterator it = node->children().begin();
125 for (; it != node->children().end(); ++it)
126 count += CountNodes(*it);
131 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesWaiter);
135 class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase {
137 explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager)
138 : TreeObserverBase(view_manager) {}
139 virtual ~HierarchyChanged_NodeCreatedObserver() {}
142 // Overridden from TreeObserverBase:
143 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
144 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
146 return params.receiver == view_manager()->tree() &&
147 !params.old_parent &&
148 params.new_parent == view_manager()->tree();
151 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeCreatedObserver);
154 TEST_F(ViewManagerTest, HierarchyChanged_NodeCreated) {
155 HierarchyChanged_NodeCreatedObserver observer(view_manager_2());
156 ViewTreeNode* node1 = ViewTreeNode::Create(view_manager_1());
157 view_manager_1()->tree()->AddChild(node1);
160 EXPECT_EQ(view_manager_2()->tree()->children().front()->id(), node1->id());
163 // Quits the current runloop when the root is notified about a node moved from
164 // |old_parent_id| to |new_parent_id|.
165 class HierarchyChanged_NodeMovedObserver : public TreeObserverBase {
167 HierarchyChanged_NodeMovedObserver(ViewManager* view_manager,
168 TransportNodeId old_parent_id,
169 TransportNodeId new_parent_id)
170 : TreeObserverBase(view_manager),
171 old_parent_id_(old_parent_id),
172 new_parent_id_(new_parent_id) {}
173 virtual ~HierarchyChanged_NodeMovedObserver() {}
176 // Overridden from TreeObserverBase:
177 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
178 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
180 return params.receiver == view_manager()->tree() &&
181 params.old_parent->id() == old_parent_id_&&
182 params.new_parent->id() == new_parent_id_;
185 TransportNodeId old_parent_id_;
186 TransportNodeId new_parent_id_;
188 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeMovedObserver);
191 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) {
192 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
193 ViewTreeNode* node2 = CreateNodeInParent(view_manager_1()->tree());
194 ViewTreeNode* node21 = CreateNodeInParent(node2);
195 TreeSizeMatchesWaiter waiter(view_manager_2(), 4);
197 HierarchyChanged_NodeMovedObserver observer(view_manager_2(),
201 node1->AddChild(node21);
204 ViewTreeNode* tree2 = view_manager_2()->tree();
206 EXPECT_EQ(tree2->children().size(), 2u);
207 ViewTreeNode* tree2_node1 = tree2->GetChildById(node1->id());
208 EXPECT_EQ(tree2_node1->children().size(), 1u);
209 ViewTreeNode* tree2_node2 = tree2->GetChildById(node2->id());
210 EXPECT_TRUE(tree2_node2->children().empty());
211 ViewTreeNode* tree2_node21 = tree2->GetChildById(node21->id());
212 EXPECT_EQ(tree2_node21->parent(), tree2_node1);
215 class HierarchyChanged_NodeRemovedObserver : public TreeObserverBase {
217 HierarchyChanged_NodeRemovedObserver(ViewManager* view_manager)
218 : TreeObserverBase(view_manager) {}
219 virtual ~HierarchyChanged_NodeRemovedObserver() {}
222 // Overridden from TreeObserverBase:
223 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
224 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGING)
226 return params.receiver == view_manager()->tree() &&
227 params.old_parent->id() == params.receiver->id() &&
228 params.new_parent == 0;
231 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeRemovedObserver);
234 TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) {
235 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
236 TreeSizeMatchesWaiter waiter(view_manager_2(), 2);
238 HierarchyChanged_NodeRemovedObserver observer(view_manager_2());
240 view_manager_1()->tree()->RemoveChild(node1);
243 ViewTreeNode* tree2 = view_manager_2()->tree();
245 EXPECT_TRUE(tree2->children().empty());
248 class NodeDestroyed_Waiter : public ViewTreeNodeObserver {
250 NodeDestroyed_Waiter(ViewManager* view_manager, TransportNodeId id)
252 view_manager_(view_manager) {
253 view_manager_->GetNodeById(id)->AddObserver(this);
256 virtual ~NodeDestroyed_Waiter() {
260 // Overridden from TreeObserverBase:
261 virtual void OnNodeDestroy(ViewTreeNode* node,
262 DispositionChangePhase phase) OVERRIDE {
263 if (phase != DISPOSITION_CHANGED)
265 if (node->id() == id_)
270 ViewManager* view_manager_;
272 DISALLOW_COPY_AND_ASSIGN(NodeDestroyed_Waiter);
275 TEST_F(ViewManagerTest, NodeDestroyed) {
276 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
277 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
279 // |node1| will be deleted after calling Destroy() below.
280 TransportNodeId id = node1->id();
282 NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id);
284 EXPECT_TRUE(view_manager_2()->tree()->children().empty());
287 TEST_F(ViewManagerTest, ViewManagerDestroyed) {
288 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
289 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
291 TransportNodeId id = node1->id();
292 DestroyViewManager1();
293 NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id);
295 // tree() should still be valid, since it's owned by neither connection.
296 EXPECT_TRUE(view_manager_2()->tree()->children().empty());
299 } // namespace view_manager
300 } // namespace services