OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/services/public/cpp/view_manager/view_manager.h" | 5 #include "mojo/services/public/cpp/view_manager/view_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.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" | 10 #include "mojo/services/public/cpp/view_manager/util.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 current_run_loop->Run(); | 24 current_run_loop->Run(); |
25 current_run_loop = NULL; | 25 current_run_loop = NULL; |
26 } | 26 } |
27 | 27 |
28 void QuitRunLoop() { | 28 void QuitRunLoop() { |
29 current_run_loop->Quit(); | 29 current_run_loop->Quit(); |
30 } | 30 } |
31 | 31 |
32 // ViewManager ----------------------------------------------------------------- | 32 // ViewManager ----------------------------------------------------------------- |
33 | 33 |
| 34 // These tests model synchronization of two peer connections to the view manager |
| 35 // service, that are given access to some root node. |
| 36 |
34 class ViewManagerTest : public testing::Test { | 37 class ViewManagerTest : public testing::Test { |
35 public: | 38 public: |
36 ViewManagerTest() : commit_count_(0) {} | 39 ViewManagerTest() : commit_count_(0) {} |
37 | 40 |
38 protected: | 41 protected: |
39 ViewManager* view_manager_1() { return view_manager_1_.get(); } | 42 ViewManager* view_manager_1() { return view_manager_1_.get(); } |
40 ViewManager* view_manager_2() { return view_manager_2_.get(); } | 43 ViewManager* view_manager_2() { return view_manager_2_.get(); } |
41 | 44 |
42 scoped_ptr<ViewTreeNode> CreateNodeInParent(ViewTreeNode* parent) { | 45 ViewTreeNode* CreateNodeInParent(ViewTreeNode* parent) { |
43 ViewManager* parent_manager = ViewTreeNodePrivate(parent).view_manager(); | 46 ViewManager* parent_manager = ViewTreeNodePrivate(parent).view_manager(); |
44 scoped_ptr<ViewTreeNode> node(new ViewTreeNode(parent_manager)); | 47 ViewTreeNode* node = ViewTreeNode::Create(parent_manager); |
45 parent->AddChild(node.get()); | 48 parent->AddChild(node); |
46 return node.Pass(); | 49 return node; |
| 50 } |
| 51 |
| 52 void DestroyViewManager1() { |
| 53 view_manager_1_.reset(); |
47 } | 54 } |
48 | 55 |
49 private: | 56 private: |
50 // Overridden from testing::Test: | 57 // Overridden from testing::Test: |
51 virtual void SetUp() OVERRIDE { | 58 virtual void SetUp() OVERRIDE { |
52 test_helper_.Init(); | 59 test_helper_.Init(); |
53 view_manager_1_.reset(new ViewManager(test_helper_.shell())); | 60 view_manager_1_.reset(new ViewManager(test_helper_.shell())); |
54 view_manager_2_.reset(new ViewManager(test_helper_.shell())); | 61 view_manager_2_.reset(new ViewManager(test_helper_.shell())); |
55 view_manager_1_->Init(); | 62 view_manager_1_->Init(); |
56 view_manager_2_->Init(); | 63 view_manager_2_->Init(); |
(...skipping 21 matching lines...) Expand all Loading... |
78 } | 85 } |
79 | 86 |
80 protected: | 87 protected: |
81 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) = 0; | 88 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) = 0; |
82 | 89 |
83 ViewManager* view_manager() { return view_manager_; } | 90 ViewManager* view_manager() { return view_manager_; } |
84 | 91 |
85 private: | 92 private: |
86 // Overridden from ViewTreeNodeObserver: | 93 // Overridden from ViewTreeNodeObserver: |
87 virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE { | 94 virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE { |
88 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) | |
89 return; | |
90 if (ShouldQuitRunLoop(params)) | 95 if (ShouldQuitRunLoop(params)) |
91 QuitRunLoop(); | 96 QuitRunLoop(); |
92 } | 97 } |
93 | 98 |
94 ViewManager* view_manager_; | 99 ViewManager* view_manager_; |
95 DISALLOW_COPY_AND_ASSIGN(TreeObserverBase); | 100 DISALLOW_COPY_AND_ASSIGN(TreeObserverBase); |
96 }; | 101 }; |
97 | 102 |
98 // Spins a runloop until the tree beginning at |root| has |tree_size| nodes | 103 // Spins a runloop until the tree beginning at |root| has |tree_size| nodes |
99 // (including |root|). | 104 // (including |root|). |
100 class TreeSizeMatchesWaiter : public TreeObserverBase { | 105 class TreeSizeMatchesWaiter : public TreeObserverBase { |
101 public: | 106 public: |
102 TreeSizeMatchesWaiter(ViewManager* view_manager, size_t tree_size) | 107 TreeSizeMatchesWaiter(ViewManager* view_manager, size_t tree_size) |
103 : TreeObserverBase(view_manager), | 108 : TreeObserverBase(view_manager), |
104 tree_size_(tree_size) { | 109 tree_size_(tree_size) { |
105 DoRunLoop(); | 110 DoRunLoop(); |
106 } | 111 } |
107 virtual ~TreeSizeMatchesWaiter() {} | 112 virtual ~TreeSizeMatchesWaiter() {} |
108 | 113 |
109 private: | 114 private: |
110 // Overridden from TreeObserverBase: | 115 // Overridden from TreeObserverBase: |
111 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { | 116 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { |
| 117 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 118 return false; |
112 return CountNodes(view_manager()->tree()) == tree_size_; | 119 return CountNodes(view_manager()->tree()) == tree_size_; |
113 } | 120 } |
114 | 121 |
115 size_t CountNodes(ViewTreeNode* node) const { | 122 size_t CountNodes(ViewTreeNode* node) const { |
116 size_t count = 1; | 123 size_t count = 1; |
117 ViewTreeNode::Children::const_iterator it = node->children().begin(); | 124 ViewTreeNode::Children::const_iterator it = node->children().begin(); |
118 for (; it != node->children().end(); ++it) | 125 for (; it != node->children().end(); ++it) |
119 count += CountNodes(*it); | 126 count += CountNodes(*it); |
120 return count; | 127 return count; |
121 } | 128 } |
122 | 129 |
123 size_t tree_size_; | 130 size_t tree_size_; |
124 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesWaiter); | 131 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesWaiter); |
125 }; | 132 }; |
126 | 133 |
127 | 134 |
128 class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase { | 135 class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase { |
129 public: | 136 public: |
130 explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager) | 137 explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager) |
131 : TreeObserverBase(view_manager) {} | 138 : TreeObserverBase(view_manager) {} |
132 virtual ~HierarchyChanged_NodeCreatedObserver() {} | 139 virtual ~HierarchyChanged_NodeCreatedObserver() {} |
133 | 140 |
134 private: | 141 private: |
135 // Overridden from TreeObserverBase: | 142 // Overridden from TreeObserverBase: |
136 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { | 143 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { |
| 144 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 145 return false; |
137 return params.receiver == view_manager()->tree() && | 146 return params.receiver == view_manager()->tree() && |
138 !params.old_parent && | 147 !params.old_parent && |
139 params.new_parent == view_manager()->tree(); | 148 params.new_parent == view_manager()->tree(); |
140 } | 149 } |
141 | 150 |
142 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeCreatedObserver); | 151 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeCreatedObserver); |
143 }; | 152 }; |
144 | 153 |
145 TEST_F(ViewManagerTest, HierarchyChanged_NodeCreated) { | 154 TEST_F(ViewManagerTest, HierarchyChanged_NodeCreated) { |
146 HierarchyChanged_NodeCreatedObserver observer(view_manager_2()); | 155 HierarchyChanged_NodeCreatedObserver observer(view_manager_2()); |
147 scoped_ptr<ViewTreeNode> node1(new ViewTreeNode(view_manager_1())); | 156 ViewTreeNode* node1 = ViewTreeNode::Create(view_manager_1()); |
148 view_manager_1()->tree()->AddChild(node1.get()); | 157 view_manager_1()->tree()->AddChild(node1); |
149 DoRunLoop(); | 158 DoRunLoop(); |
150 | 159 |
151 EXPECT_EQ(view_manager_2()->tree()->children().front()->id(), node1->id()); | 160 EXPECT_EQ(view_manager_2()->tree()->children().front()->id(), node1->id()); |
152 } | 161 } |
153 | 162 |
154 // Quits the current runloop when the root is notified about a node moved from | 163 // Quits the current runloop when the root is notified about a node moved from |
155 // |old_parent_id| to |new_parent_id|. | 164 // |old_parent_id| to |new_parent_id|. |
156 class HierarchyChanged_NodeMovedObserver : public TreeObserverBase { | 165 class HierarchyChanged_NodeMovedObserver : public TreeObserverBase { |
157 public: | 166 public: |
158 HierarchyChanged_NodeMovedObserver(ViewManager* view_manager, | 167 HierarchyChanged_NodeMovedObserver(ViewManager* view_manager, |
159 TransportNodeId old_parent_id, | 168 TransportNodeId old_parent_id, |
160 TransportNodeId new_parent_id) | 169 TransportNodeId new_parent_id) |
161 : TreeObserverBase(view_manager), | 170 : TreeObserverBase(view_manager), |
162 old_parent_id_(old_parent_id), | 171 old_parent_id_(old_parent_id), |
163 new_parent_id_(new_parent_id) {} | 172 new_parent_id_(new_parent_id) {} |
164 virtual ~HierarchyChanged_NodeMovedObserver() {} | 173 virtual ~HierarchyChanged_NodeMovedObserver() {} |
165 | 174 |
166 private: | 175 private: |
167 // Overridden from TreeObserverBase: | 176 // Overridden from TreeObserverBase: |
168 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { | 177 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { |
| 178 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 179 return false; |
169 return params.receiver == view_manager()->tree() && | 180 return params.receiver == view_manager()->tree() && |
170 params.old_parent->id() == old_parent_id_&& | 181 params.old_parent->id() == old_parent_id_&& |
171 params.new_parent->id() == new_parent_id_; | 182 params.new_parent->id() == new_parent_id_; |
172 } | 183 } |
173 | 184 |
174 TransportNodeId old_parent_id_; | 185 TransportNodeId old_parent_id_; |
175 TransportNodeId new_parent_id_; | 186 TransportNodeId new_parent_id_; |
176 | 187 |
177 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeMovedObserver); | 188 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeMovedObserver); |
178 }; | 189 }; |
179 | 190 |
180 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) { | 191 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) { |
181 scoped_ptr<ViewTreeNode> node1(CreateNodeInParent(view_manager_1()->tree())); | 192 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
182 scoped_ptr<ViewTreeNode> node2(CreateNodeInParent(view_manager_1()->tree())); | 193 ViewTreeNode* node2 = CreateNodeInParent(view_manager_1()->tree()); |
183 scoped_ptr<ViewTreeNode> node21(CreateNodeInParent(node2.get())); | 194 ViewTreeNode* node21 = CreateNodeInParent(node2); |
184 TreeSizeMatchesWaiter waiter(view_manager_2(), 4); | 195 TreeSizeMatchesWaiter waiter(view_manager_2(), 4); |
185 | 196 |
186 HierarchyChanged_NodeMovedObserver observer(view_manager_2(), | 197 HierarchyChanged_NodeMovedObserver observer(view_manager_2(), |
187 node2->id(), | 198 node2->id(), |
188 node1->id()); | 199 node1->id()); |
189 | 200 |
190 node1->AddChild(node21.get()); | 201 node1->AddChild(node21); |
191 DoRunLoop(); | 202 DoRunLoop(); |
192 | 203 |
193 ViewTreeNode* tree2 = view_manager_2()->tree(); | 204 ViewTreeNode* tree2 = view_manager_2()->tree(); |
194 | 205 |
195 EXPECT_EQ(tree2->children().size(), 2u); | 206 EXPECT_EQ(tree2->children().size(), 2u); |
196 ViewTreeNode* tree2_node1 = tree2->GetChildById(node1->id()); | 207 ViewTreeNode* tree2_node1 = tree2->GetChildById(node1->id()); |
197 EXPECT_EQ(tree2_node1->children().size(), 1u); | 208 EXPECT_EQ(tree2_node1->children().size(), 1u); |
198 ViewTreeNode* tree2_node2 = tree2->GetChildById(node2->id()); | 209 ViewTreeNode* tree2_node2 = tree2->GetChildById(node2->id()); |
199 EXPECT_TRUE(tree2_node2->children().empty()); | 210 EXPECT_TRUE(tree2_node2->children().empty()); |
200 ViewTreeNode* tree2_node21 = tree2->GetChildById(node21->id()); | 211 ViewTreeNode* tree2_node21 = tree2->GetChildById(node21->id()); |
201 EXPECT_EQ(tree2_node21->parent(), tree2_node1); | 212 EXPECT_EQ(tree2_node21->parent(), tree2_node1); |
202 } | 213 } |
203 | 214 |
204 // TODO(beng): node destruction | 215 class HierarchyChanged_NodeRemovedObserver : public TreeObserverBase { |
| 216 public: |
| 217 HierarchyChanged_NodeRemovedObserver(ViewManager* view_manager) |
| 218 : TreeObserverBase(view_manager) {} |
| 219 virtual ~HierarchyChanged_NodeRemovedObserver() {} |
| 220 |
| 221 private: |
| 222 // Overridden from TreeObserverBase: |
| 223 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { |
| 224 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGING) |
| 225 return false; |
| 226 return params.receiver == view_manager()->tree() && |
| 227 params.old_parent->id() == params.receiver->id() && |
| 228 params.new_parent == 0; |
| 229 } |
| 230 |
| 231 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeRemovedObserver); |
| 232 }; |
| 233 |
| 234 TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) { |
| 235 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
| 236 TreeSizeMatchesWaiter waiter(view_manager_2(), 2); |
| 237 |
| 238 HierarchyChanged_NodeRemovedObserver observer(view_manager_2()); |
| 239 |
| 240 view_manager_1()->tree()->RemoveChild(node1); |
| 241 DoRunLoop(); |
| 242 |
| 243 ViewTreeNode* tree2 = view_manager_2()->tree(); |
| 244 |
| 245 EXPECT_TRUE(tree2->children().empty()); |
| 246 } |
| 247 |
| 248 class NodeDestroyed_Waiter : public ViewTreeNodeObserver { |
| 249 public: |
| 250 NodeDestroyed_Waiter(ViewManager* view_manager, TransportNodeId id) |
| 251 : id_(id), |
| 252 view_manager_(view_manager) { |
| 253 view_manager_->GetNodeById(id)->AddObserver(this); |
| 254 DoRunLoop(); |
| 255 } |
| 256 virtual ~NodeDestroyed_Waiter() { |
| 257 } |
| 258 |
| 259 private: |
| 260 // Overridden from TreeObserverBase: |
| 261 virtual void OnNodeDestroy(ViewTreeNode* node, |
| 262 DispositionChangePhase phase) OVERRIDE { |
| 263 if (phase != DISPOSITION_CHANGED) |
| 264 return; |
| 265 if (node->id() == id_) |
| 266 QuitRunLoop(); |
| 267 } |
| 268 |
| 269 TransportNodeId id_; |
| 270 ViewManager* view_manager_; |
| 271 |
| 272 DISALLOW_COPY_AND_ASSIGN(NodeDestroyed_Waiter); |
| 273 }; |
| 274 |
| 275 TEST_F(ViewManagerTest, NodeDestroyed) { |
| 276 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
| 277 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); |
| 278 |
| 279 // |node1| will be deleted after calling Destroy() below. |
| 280 TransportNodeId id = node1->id(); |
| 281 node1->Destroy(); |
| 282 NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id); |
| 283 |
| 284 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); |
| 285 } |
| 286 |
| 287 TEST_F(ViewManagerTest, ViewManagerDestroyed) { |
| 288 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
| 289 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); |
| 290 |
| 291 TransportNodeId id = node1->id(); |
| 292 DestroyViewManager1(); |
| 293 NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id); |
| 294 |
| 295 // tree() should still be valid, since it's owned by neither connection. |
| 296 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); |
| 297 } |
205 | 298 |
206 } // namespace view_manager | 299 } // namespace view_manager |
207 } // namespace services | 300 } // namespace services |
208 } // namespace mojo | 301 } // namespace mojo |
OLD | NEW |