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_manager_private.h" |
| 10 #include "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h" |
9 #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" | 11 #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" |
10 #include "mojo/services/public/cpp/view_manager/util.h" | 12 #include "mojo/services/public/cpp/view_manager/util.h" |
11 #include "mojo/services/public/cpp/view_manager/view.h" | 13 #include "mojo/services/public/cpp/view_manager/view.h" |
12 #include "mojo/services/public/cpp/view_manager/view_observer.h" | 14 #include "mojo/services/public/cpp/view_manager/view_observer.h" |
13 #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" | 15 #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" |
14 #include "mojo/shell/shell_test_helper.h" | 16 #include "mojo/shell/shell_test_helper.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
16 | 18 |
17 namespace mojo { | 19 namespace mojo { |
18 namespace view_manager { | 20 namespace view_manager { |
19 | 21 |
20 base::RunLoop* current_run_loop = NULL; | 22 base::RunLoop* current_run_loop = NULL; |
21 | 23 |
22 void DoRunLoop() { | 24 void DoRunLoop() { |
23 base::RunLoop run_loop; | 25 base::RunLoop run_loop; |
24 current_run_loop = &run_loop; | 26 current_run_loop = &run_loop; |
25 current_run_loop->Run(); | 27 current_run_loop->Run(); |
26 current_run_loop = NULL; | 28 current_run_loop = NULL; |
27 } | 29 } |
28 | 30 |
29 void QuitRunLoop() { | 31 void QuitRunLoop() { |
30 current_run_loop->Quit(); | 32 current_run_loop->Quit(); |
31 } | 33 } |
32 | 34 |
| 35 void QuitRunLoopOnChangesAcked() { |
| 36 QuitRunLoop(); |
| 37 } |
| 38 |
| 39 void WaitForAllChangesToBeAcked(ViewManager* manager) { |
| 40 ViewManagerPrivate(manager).synchronizer()->set_changes_acked_callback( |
| 41 base::Bind(&QuitRunLoopOnChangesAcked)); |
| 42 DoRunLoop(); |
| 43 ViewManagerPrivate(manager).synchronizer()->ClearChangesAckedCallback(); |
| 44 } |
| 45 |
| 46 class ActiveViewChangedObserver : public ViewTreeNodeObserver { |
| 47 public: |
| 48 explicit ActiveViewChangedObserver(ViewTreeNode* node) |
| 49 : node_(node) {} |
| 50 virtual ~ActiveViewChangedObserver() {} |
| 51 |
| 52 private: |
| 53 // Overridden from ViewTreeNodeObserver: |
| 54 virtual void OnNodeActiveViewChange(ViewTreeNode* node, |
| 55 View* old_view, |
| 56 View* new_view, |
| 57 DispositionChangePhase phase) OVERRIDE { |
| 58 DCHECK_EQ(node, node_); |
| 59 QuitRunLoop(); |
| 60 } |
| 61 |
| 62 ViewTreeNode* node_; |
| 63 |
| 64 DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedObserver); |
| 65 }; |
| 66 |
| 67 // Waits until the active view id of the supplied node changes. |
| 68 void WaitForActiveViewToChange(ViewTreeNode* node) { |
| 69 ActiveViewChangedObserver observer(node); |
| 70 node->AddObserver(&observer); |
| 71 DoRunLoop(); |
| 72 node->RemoveObserver(&observer); |
| 73 } |
| 74 |
| 75 // Spins a runloop until the tree beginning at |root| has |tree_size| nodes |
| 76 // (including |root|). |
| 77 class TreeSizeMatchesObserver : public ViewTreeNodeObserver { |
| 78 public: |
| 79 TreeSizeMatchesObserver(ViewTreeNode* tree, size_t tree_size) |
| 80 : tree_(tree), |
| 81 tree_size_(tree_size) {} |
| 82 virtual ~TreeSizeMatchesObserver() {} |
| 83 |
| 84 bool IsTreeCorrectSize() { |
| 85 return CountNodes(tree_) == tree_size_; |
| 86 } |
| 87 |
| 88 private: |
| 89 // Overridden from ViewTreeNodeObserver: |
| 90 virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE { |
| 91 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 92 return; |
| 93 if (IsTreeCorrectSize()) |
| 94 QuitRunLoop(); |
| 95 } |
| 96 |
| 97 size_t CountNodes(const ViewTreeNode* node) const { |
| 98 size_t count = 1; |
| 99 ViewTreeNode::Children::const_iterator it = node->children().begin(); |
| 100 for (; it != node->children().end(); ++it) |
| 101 count += CountNodes(*it); |
| 102 return count; |
| 103 } |
| 104 |
| 105 ViewTreeNode* tree_; |
| 106 size_t tree_size_; |
| 107 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); |
| 108 }; |
| 109 |
| 110 void WaitForTreeSizeToMatch(ViewTreeNode* node, size_t tree_size) { |
| 111 TreeSizeMatchesObserver observer(node, tree_size); |
| 112 if (observer.IsTreeCorrectSize()) |
| 113 return; |
| 114 node->AddObserver(&observer); |
| 115 DoRunLoop(); |
| 116 node->RemoveObserver(&observer); |
| 117 } |
| 118 |
| 119 |
| 120 // Utility class that waits for the destruction of some number of nodes and |
| 121 // views. |
| 122 class DestructionObserver : public ViewTreeNodeObserver, |
| 123 public ViewObserver { |
| 124 public: |
| 125 // |nodes| or |views| can be NULL. |
| 126 DestructionObserver(std::set<TransportNodeId>* nodes, |
| 127 std::set<TransportViewId>* views) |
| 128 : nodes_(nodes), |
| 129 views_(views) {} |
| 130 |
| 131 private: |
| 132 // Overridden from ViewTreeNodeObserver: |
| 133 virtual void OnNodeDestroy( |
| 134 ViewTreeNode* node, |
| 135 ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE { |
| 136 if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 137 return; |
| 138 std::set<TransportNodeId>::const_iterator it = nodes_->find(node->id()); |
| 139 if (it != nodes_->end()) |
| 140 nodes_->erase(it); |
| 141 if (CanQuit()) |
| 142 QuitRunLoop(); |
| 143 } |
| 144 |
| 145 // Overridden from ViewObserver: |
| 146 virtual void OnViewDestroy( |
| 147 View* view, |
| 148 ViewObserver::DispositionChangePhase phase) OVERRIDE { |
| 149 if (phase != ViewObserver::DISPOSITION_CHANGED) |
| 150 return; |
| 151 std::set<TransportViewId>::const_iterator it = views_->find(view->id()); |
| 152 if (it != views_->end()) |
| 153 views_->erase(it); |
| 154 if (CanQuit()) |
| 155 QuitRunLoop(); |
| 156 } |
| 157 |
| 158 bool CanQuit() { |
| 159 return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty()); |
| 160 } |
| 161 |
| 162 std::set<TransportNodeId>* nodes_; |
| 163 std::set<TransportViewId>* views_; |
| 164 |
| 165 DISALLOW_COPY_AND_ASSIGN(DestructionObserver); |
| 166 }; |
| 167 |
| 168 void WaitForDestruction(ViewManager* view_manager, |
| 169 std::set<TransportNodeId>* nodes, |
| 170 std::set<TransportViewId>* views) { |
| 171 DestructionObserver observer(nodes, views); |
| 172 DCHECK(nodes || views); |
| 173 if (nodes) { |
| 174 for (std::set<TransportNodeId>::const_iterator it = nodes->begin(); |
| 175 it != nodes->end(); ++it) { |
| 176 view_manager->GetNodeById(*it)->AddObserver(&observer); |
| 177 } |
| 178 } |
| 179 if (views) { |
| 180 for (std::set<TransportViewId>::const_iterator it = views->begin(); |
| 181 it != views->end(); ++it) { |
| 182 view_manager->GetViewById(*it)->AddObserver(&observer); |
| 183 } |
| 184 } |
| 185 DoRunLoop(); |
| 186 } |
| 187 |
33 // ViewManager ----------------------------------------------------------------- | 188 // ViewManager ----------------------------------------------------------------- |
34 | 189 |
35 // These tests model synchronization of two peer connections to the view manager | 190 // These tests model synchronization of two peer connections to the view manager |
36 // service, that are given access to some root node. | 191 // service, that are given access to some root node. |
37 | 192 |
38 class ViewManagerTest : public testing::Test { | 193 class ViewManagerTest : public testing::Test { |
39 public: | 194 public: |
40 ViewManagerTest() : commit_count_(0) {} | 195 ViewManagerTest() : commit_count_(0) {} |
41 | 196 |
42 protected: | 197 protected: |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 // Overridden from ViewTreeNodeObserver: | 249 // Overridden from ViewTreeNodeObserver: |
95 virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE { | 250 virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE { |
96 if (ShouldQuitRunLoop(params)) | 251 if (ShouldQuitRunLoop(params)) |
97 QuitRunLoop(); | 252 QuitRunLoop(); |
98 } | 253 } |
99 | 254 |
100 ViewManager* view_manager_; | 255 ViewManager* view_manager_; |
101 DISALLOW_COPY_AND_ASSIGN(TreeObserverBase); | 256 DISALLOW_COPY_AND_ASSIGN(TreeObserverBase); |
102 }; | 257 }; |
103 | 258 |
104 // Spins a runloop until the tree beginning at |root| has |tree_size| nodes | |
105 // (including |root|). | |
106 class TreeSizeMatchesWaiter : public TreeObserverBase { | |
107 public: | |
108 TreeSizeMatchesWaiter(ViewManager* view_manager, size_t tree_size) | |
109 : TreeObserverBase(view_manager), | |
110 tree_size_(tree_size) { | |
111 DoRunLoop(); | |
112 } | |
113 virtual ~TreeSizeMatchesWaiter() {} | |
114 | |
115 private: | |
116 // Overridden from TreeObserverBase: | |
117 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { | |
118 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) | |
119 return false; | |
120 return CountNodes(view_manager()->tree()) == tree_size_; | |
121 } | |
122 | |
123 size_t CountNodes(ViewTreeNode* node) const { | |
124 size_t count = 1; | |
125 ViewTreeNode::Children::const_iterator it = node->children().begin(); | |
126 for (; it != node->children().end(); ++it) | |
127 count += CountNodes(*it); | |
128 return count; | |
129 } | |
130 | |
131 size_t tree_size_; | |
132 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesWaiter); | |
133 }; | |
134 | |
135 | |
136 class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase { | 259 class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase { |
137 public: | 260 public: |
138 explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager) | 261 explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager) |
139 : TreeObserverBase(view_manager) {} | 262 : TreeObserverBase(view_manager) {} |
140 virtual ~HierarchyChanged_NodeCreatedObserver() {} | 263 virtual ~HierarchyChanged_NodeCreatedObserver() {} |
141 | 264 |
142 private: | 265 private: |
143 // Overridden from TreeObserverBase: | 266 // Overridden from TreeObserverBase: |
144 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { | 267 virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE { |
145 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) | 268 if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 TransportNodeId old_parent_id_; | 309 TransportNodeId old_parent_id_; |
187 TransportNodeId new_parent_id_; | 310 TransportNodeId new_parent_id_; |
188 | 311 |
189 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeMovedObserver); | 312 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeMovedObserver); |
190 }; | 313 }; |
191 | 314 |
192 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) { | 315 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) { |
193 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 316 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
194 ViewTreeNode* node2 = CreateNodeInParent(view_manager_1()->tree()); | 317 ViewTreeNode* node2 = CreateNodeInParent(view_manager_1()->tree()); |
195 ViewTreeNode* node21 = CreateNodeInParent(node2); | 318 ViewTreeNode* node21 = CreateNodeInParent(node2); |
196 TreeSizeMatchesWaiter waiter(view_manager_2(), 4); | 319 WaitForTreeSizeToMatch(view_manager_2()->tree(), 4); |
197 | 320 |
198 HierarchyChanged_NodeMovedObserver observer(view_manager_2(), | 321 HierarchyChanged_NodeMovedObserver observer(view_manager_2(), |
199 node2->id(), | 322 node2->id(), |
200 node1->id()); | 323 node1->id()); |
201 | 324 |
202 node1->AddChild(node21); | 325 node1->AddChild(node21); |
203 DoRunLoop(); | 326 DoRunLoop(); |
204 | 327 |
205 ViewTreeNode* tree2 = view_manager_2()->tree(); | 328 ViewTreeNode* tree2 = view_manager_2()->tree(); |
206 | 329 |
(...skipping 20 matching lines...) Expand all Loading... |
227 return params.receiver == view_manager()->tree() && | 350 return params.receiver == view_manager()->tree() && |
228 params.old_parent->id() == params.receiver->id() && | 351 params.old_parent->id() == params.receiver->id() && |
229 params.new_parent == 0; | 352 params.new_parent == 0; |
230 } | 353 } |
231 | 354 |
232 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeRemovedObserver); | 355 DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeRemovedObserver); |
233 }; | 356 }; |
234 | 357 |
235 TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) { | 358 TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) { |
236 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 359 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
237 TreeSizeMatchesWaiter waiter(view_manager_2(), 2); | 360 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
238 | 361 |
239 HierarchyChanged_NodeRemovedObserver observer(view_manager_2()); | 362 HierarchyChanged_NodeRemovedObserver observer(view_manager_2()); |
240 | 363 |
241 view_manager_1()->tree()->RemoveChild(node1); | 364 view_manager_1()->tree()->RemoveChild(node1); |
242 DoRunLoop(); | 365 DoRunLoop(); |
243 | 366 |
244 ViewTreeNode* tree2 = view_manager_2()->tree(); | 367 ViewTreeNode* tree2 = view_manager_2()->tree(); |
245 | 368 |
246 EXPECT_TRUE(tree2->children().empty()); | 369 EXPECT_TRUE(tree2->children().empty()); |
247 } | 370 } |
248 | 371 |
249 // Utility class that waits for the destruction of some number of nodes and | |
250 // views. | |
251 class DestructionWaiter : public ViewTreeNodeObserver, | |
252 public ViewObserver { | |
253 public: | |
254 // |nodes| or |views| can be NULL. | |
255 DestructionWaiter(ViewManager* view_manager, | |
256 std::set<TransportNodeId>* nodes, | |
257 std::set<TransportViewId>* views) | |
258 : nodes_(nodes), | |
259 views_(views) { | |
260 DCHECK(nodes || views); | |
261 if (nodes) { | |
262 for (std::set<TransportNodeId>::const_iterator it = nodes->begin(); | |
263 it != nodes->end(); ++it) { | |
264 view_manager->GetNodeById(*it)->AddObserver(this); | |
265 } | |
266 } | |
267 if (views) { | |
268 for (std::set<TransportViewId>::const_iterator it = views->begin(); | |
269 it != views->end(); ++it) { | |
270 view_manager->GetViewById(*it)->AddObserver(this); | |
271 } | |
272 } | |
273 DoRunLoop(); | |
274 } | |
275 | |
276 private: | |
277 // Overridden from ViewTreeNodeObserver: | |
278 virtual void OnNodeDestroy( | |
279 ViewTreeNode* node, | |
280 ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE { | |
281 if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) | |
282 return; | |
283 std::set<TransportNodeId>::const_iterator it = nodes_->find(node->id()); | |
284 if (it != nodes_->end()) | |
285 nodes_->erase(it); | |
286 if (CanQuit()) | |
287 QuitRunLoop(); | |
288 } | |
289 | |
290 // Overridden from ViewObserver: | |
291 virtual void OnViewDestroy( | |
292 View* view, | |
293 ViewObserver::DispositionChangePhase phase) OVERRIDE { | |
294 if (phase != ViewObserver::DISPOSITION_CHANGED) | |
295 return; | |
296 std::set<TransportViewId>::const_iterator it = views_->find(view->id()); | |
297 if (it != views_->end()) | |
298 views_->erase(it); | |
299 if (CanQuit()) | |
300 QuitRunLoop(); | |
301 } | |
302 | |
303 bool CanQuit() { | |
304 return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty()); | |
305 } | |
306 | |
307 std::set<TransportNodeId>* nodes_; | |
308 std::set<TransportViewId>* views_; | |
309 | |
310 DISALLOW_COPY_AND_ASSIGN(DestructionWaiter); | |
311 }; | |
312 | |
313 TEST_F(ViewManagerTest, NodeDestroyed) { | 372 TEST_F(ViewManagerTest, NodeDestroyed) { |
314 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 373 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
315 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 374 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
316 | 375 |
317 // |node1| will be deleted after calling Destroy() below. | 376 // |node1| will be deleted after calling Destroy() below. |
318 TransportNodeId id = node1->id(); | 377 TransportNodeId id = node1->id(); |
319 node1->Destroy(); | 378 node1->Destroy(); |
320 | 379 |
321 std::set<TransportNodeId> nodes; | 380 std::set<TransportNodeId> nodes; |
322 nodes.insert(id); | 381 nodes.insert(id); |
323 DestructionWaiter destroyed_waiter(view_manager_2(), &nodes, NULL); | 382 WaitForDestruction(view_manager_2(), &nodes, NULL); |
324 | 383 |
325 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | 384 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); |
326 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(id)); | 385 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(id)); |
327 } | 386 } |
328 | 387 |
329 TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) { | 388 TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) { |
330 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 389 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
331 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 390 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
332 | 391 |
333 TransportNodeId id = node1->id(); | 392 TransportNodeId id = node1->id(); |
334 DestroyViewManager1(); | 393 DestroyViewManager1(); |
335 std::set<TransportNodeId> nodes; | 394 std::set<TransportNodeId> nodes; |
336 nodes.insert(id); | 395 nodes.insert(id); |
337 DestructionWaiter destroyed_waiter(view_manager_2(), &nodes, NULL); | 396 WaitForDestruction(view_manager_2(), &nodes, NULL); |
338 | 397 |
339 // tree() should still be valid, since it's owned by neither connection. | 398 // tree() should still be valid, since it's owned by neither connection. |
340 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | 399 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); |
341 } | 400 } |
342 | 401 |
343 // Waits until the active view id of the supplied node changes. | |
344 class ActiveViewChangedWaiter : public ViewTreeNodeObserver { | |
345 public: | |
346 explicit ActiveViewChangedWaiter(ViewTreeNode* node) | |
347 : node_(node) { | |
348 node_->AddObserver(this); | |
349 DoRunLoop(); | |
350 } | |
351 virtual ~ActiveViewChangedWaiter() { | |
352 node_->RemoveObserver(this); | |
353 } | |
354 | |
355 private: | |
356 // Overridden from ViewTreeNodeObserver: | |
357 virtual void OnNodeActiveViewChange(ViewTreeNode* node, | |
358 View* old_view, | |
359 View* new_view, | |
360 DispositionChangePhase phase) OVERRIDE { | |
361 DCHECK_EQ(node, node_); | |
362 QuitRunLoop(); | |
363 } | |
364 | |
365 ViewTreeNode* node_; | |
366 | |
367 DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedWaiter); | |
368 }; | |
369 | |
370 TEST_F(ViewManagerTest, SetActiveView) { | 402 TEST_F(ViewManagerTest, SetActiveView) { |
371 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 403 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
372 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 404 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
373 | 405 |
374 View* view1 = View::Create(view_manager_1()); | 406 View* view1 = View::Create(view_manager_1()); |
375 node1->SetActiveView(view1); | 407 node1->SetActiveView(view1); |
376 | 408 |
377 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); | 409 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); |
378 ActiveViewChangedWaiter waiter(node1_2); | 410 WaitForActiveViewToChange(node1_2); |
379 | 411 |
380 EXPECT_EQ(node1_2->active_view()->id(), view1->id()); | 412 EXPECT_EQ(node1_2->active_view()->id(), view1->id()); |
381 } | 413 } |
382 | 414 |
383 TEST_F(ViewManagerTest, DestroyView) { | 415 TEST_F(ViewManagerTest, DestroyView) { |
384 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 416 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
385 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 417 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
386 | 418 |
387 View* view1 = View::Create(view_manager_1()); | 419 View* view1 = View::Create(view_manager_1()); |
388 node1->SetActiveView(view1); | 420 node1->SetActiveView(view1); |
389 | 421 |
390 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); | 422 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); |
391 ActiveViewChangedWaiter active_view_waiter(node1_2); | 423 WaitForActiveViewToChange(node1_2); |
392 | 424 |
393 TransportViewId view1_id = view1->id(); | 425 TransportViewId view1_id = view1->id(); |
394 view1->Destroy(); | 426 view1->Destroy(); |
395 | 427 |
396 std::set<TransportViewId> views; | 428 std::set<TransportViewId> views; |
397 views.insert(view1_id); | 429 views.insert(view1_id); |
398 DestructionWaiter destruction_waiter(view_manager_2(), NULL, &views); | 430 WaitForDestruction(view_manager_2(), NULL, &views); |
399 EXPECT_EQ(NULL, node1_2->active_view()); | 431 EXPECT_EQ(NULL, node1_2->active_view()); |
400 EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); | 432 EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); |
401 } | 433 } |
402 | 434 |
403 // Destroying the connection that created a node and view should result in that | 435 // Destroying the connection that created a node and view should result in that |
404 // node and view disappearing from all connections that see them. | 436 // node and view disappearing from all connections that see them. |
405 TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) { | 437 TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) { |
406 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 438 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
407 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 439 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
408 | 440 |
409 View* view1 = View::Create(view_manager_1()); | 441 View* view1 = View::Create(view_manager_1()); |
410 node1->SetActiveView(view1); | 442 node1->SetActiveView(view1); |
411 | 443 |
412 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); | 444 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); |
413 { | 445 WaitForActiveViewToChange(node1_2); |
414 ActiveViewChangedWaiter active_view_waiter(node1_2); | |
415 } | |
416 | 446 |
417 TransportNodeId node1_id = node1->id(); | 447 TransportNodeId node1_id = node1->id(); |
418 TransportViewId view1_id = view1->id(); | 448 TransportViewId view1_id = view1->id(); |
419 | 449 |
420 DestroyViewManager1(); | 450 DestroyViewManager1(); |
421 std::set<TransportNodeId> observed_nodes; | 451 std::set<TransportNodeId> observed_nodes; |
422 observed_nodes.insert(node1_id); | 452 observed_nodes.insert(node1_id); |
423 std::set<TransportViewId> observed_views; | 453 std::set<TransportViewId> observed_views; |
424 observed_views.insert(view1_id); | 454 observed_views.insert(view1_id); |
425 DestructionWaiter destruction_waiter(view_manager_2(), | 455 WaitForDestruction(view_manager_2(), &observed_nodes, &observed_views); |
426 &observed_nodes, | |
427 &observed_views); | |
428 | 456 |
429 // tree() should still be valid, since it's owned by neither connection. | 457 // tree() should still be valid, since it's owned by neither connection. |
430 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | 458 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); |
431 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); | 459 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); |
432 EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); | 460 EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); |
433 } | 461 } |
434 | 462 |
435 // This test validates the following scenario: | 463 // This test validates the following scenario: |
436 // - a node originating from one connection | 464 // - a node originating from one connection |
437 // - a view originating from a second connection | 465 // - a view originating from a second connection |
438 // + the connection originating the node is destroyed | 466 // + the connection originating the node is destroyed |
439 // -> the view should still exist (since the second connection is live) but | 467 // -> the view should still exist (since the second connection is live) but |
440 // should be disconnected from any nodes. | 468 // should be disconnected from any nodes. |
441 TEST_F(ViewManagerTest, | 469 TEST_F(ViewManagerTest, |
442 ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) { | 470 ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) { |
443 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 471 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
444 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 472 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
445 | 473 |
446 View* view1_2 = View::Create(view_manager_2()); | 474 View* view1_2 = View::Create(view_manager_2()); |
447 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); | 475 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); |
448 node1_2->SetActiveView(view1_2); | 476 node1_2->SetActiveView(view1_2); |
449 | 477 WaitForActiveViewToChange(node1); |
450 { | |
451 ActiveViewChangedWaiter active_view_waiter(node1); | |
452 } | |
453 | 478 |
454 TransportNodeId node1_id = node1->id(); | 479 TransportNodeId node1_id = node1->id(); |
455 TransportViewId view1_2_id = view1_2->id(); | 480 TransportViewId view1_2_id = view1_2->id(); |
456 | 481 |
457 DestroyViewManager1(); | 482 DestroyViewManager1(); |
458 std::set<TransportNodeId> nodes; | 483 std::set<TransportNodeId> nodes; |
459 nodes.insert(node1_id); | 484 nodes.insert(node1_id); |
460 DestructionWaiter destruction_waiter(view_manager_2(), &nodes, NULL); | 485 WaitForDestruction(view_manager_2(), &nodes, NULL); |
461 | 486 |
462 // tree() should still be valid, since it's owned by neither connection. | 487 // tree() should still be valid, since it's owned by neither connection. |
463 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | 488 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); |
464 // node1 was owned by the first connection, so it should be gone. | 489 // node1 was owned by the first connection, so it should be gone. |
465 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); | 490 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); |
466 // view1_2 was owned by the second connection, so it should still exist, but | 491 // view1_2 was owned by the second connection, so it should still exist, but |
467 // disconnected from the node tree. | 492 // disconnected from the node tree. |
468 View* another_view1_2 = view_manager_2()->GetViewById(view1_2_id); | 493 View* another_view1_2 = view_manager_2()->GetViewById(view1_2_id); |
469 EXPECT_EQ(view1_2, another_view1_2); | 494 EXPECT_EQ(view1_2, another_view1_2); |
470 EXPECT_EQ(NULL, view1_2->node()); | 495 EXPECT_EQ(NULL, view1_2->node()); |
471 } | 496 } |
472 | 497 |
473 // This test verifies that it is not possible to set the active view to a view | 498 // This test verifies that it is not possible to set the active view to a view |
474 // defined in a different connection. | 499 // defined in a different connection. |
475 // TODO(beng): write these tests for ViewTreeNode::AddChild(), RemoveChild() and | 500 // TODO(beng): write these tests for ViewTreeNode::AddChild(), RemoveChild() and |
476 // Contains(). | 501 // Contains(). |
477 TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { | 502 TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { |
478 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 503 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); |
479 TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); | 504 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); |
480 | 505 |
481 View* view1_2 = View::Create(view_manager_2()); | 506 View* view1_2 = View::Create(view_manager_2()); |
482 EXPECT_DEATH(node1->SetActiveView(view1_2), ""); | 507 EXPECT_DEATH(node1->SetActiveView(view1_2), ""); |
483 } | 508 } |
484 | 509 |
| 510 // This test verifies that a node hierarchy constructed in one connection |
| 511 // becomes entirely visible to the second connection when the hierarchy is |
| 512 // attached. |
| 513 TEST_F(ViewManagerTest, MapSubtreeOnAttach) { |
| 514 ViewTreeNode* node1 = ViewTreeNode::Create(view_manager_1()); |
| 515 ViewTreeNode* node11 = CreateNodeInParent(node1); |
| 516 View* view11 = View::Create(view_manager_1()); |
| 517 node11->SetActiveView(view11); |
| 518 WaitForAllChangesToBeAcked(view_manager_1()); |
| 519 |
| 520 // Now attach this node tree to the root & wait for it to show up in the |
| 521 // second connection. |
| 522 view_manager_1()->tree()->AddChild(node1); |
| 523 WaitForTreeSizeToMatch(view_manager_2()->tree(), 3); |
| 524 |
| 525 ViewTreeNode* node11_2 = view_manager_2()->GetNodeById(node11->id()); |
| 526 View* view11_2 = view_manager_2()->GetViewById(view11->id()); |
| 527 EXPECT_TRUE(node11_2 != NULL); |
| 528 EXPECT_EQ(view11_2, node11_2->active_view()); |
| 529 } |
| 530 |
485 } // namespace view_manager | 531 } // namespace view_manager |
486 } // namespace mojo | 532 } // namespace mojo |
OLD | NEW |