Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 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. |
| 4 | |
| 5 | #include "mojo/services/public/cpp/view_manager/view_manager.h" |
| 6 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 7 | #include "base/auto_reset.h" |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 8 | #include "base/bind.h" |
| 9 | #include "base/logging.h" |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 10 | #include "mojo/public/cpp/application/application.h" |
| 11 | #include "mojo/service_manager/service_manager.h" |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 12 | #include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h" |
| 13 | #include "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h" |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 14 | #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" |
| 15 | #include "mojo/services/public/cpp/view_manager/util.h" |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 16 | #include "mojo/services/public/cpp/view_manager/view.h" |
| 17 | #include "mojo/services/public/cpp/view_manager/view_observer.h" |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 18 | #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" |
| 19 | #include "mojo/shell/shell_test_helper.h" |
| 20 | #include "testing/gtest/include/gtest/gtest.h" |
| 21 | |
| 22 | namespace mojo { |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 23 | namespace view_manager { |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 24 | namespace { |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 25 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 26 | const char kWindowManagerURL[] = "mojo:window_manager"; |
| 27 | const char kEmbeddedApp1URL[] = "mojo:embedded_app_1"; |
| 28 | |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 29 | base::RunLoop* current_run_loop = NULL; |
| 30 | |
| 31 | void DoRunLoop() { |
| 32 | base::RunLoop run_loop; |
| 33 | current_run_loop = &run_loop; |
| 34 | current_run_loop->Run(); |
| 35 | current_run_loop = NULL; |
| 36 | } |
| 37 | |
| 38 | void QuitRunLoop() { |
| 39 | current_run_loop->Quit(); |
| 40 | } |
| 41 | |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 42 | void QuitRunLoopOnChangesAcked() { |
| 43 | QuitRunLoop(); |
| 44 | } |
| 45 | |
| 46 | void WaitForAllChangesToBeAcked(ViewManager* manager) { |
| 47 | ViewManagerPrivate(manager).synchronizer()->set_changes_acked_callback( |
| 48 | base::Bind(&QuitRunLoopOnChangesAcked)); |
| 49 | DoRunLoop(); |
| 50 | ViewManagerPrivate(manager).synchronizer()->ClearChangesAckedCallback(); |
| 51 | } |
| 52 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 53 | class ConnectServiceLoader : public ServiceLoader { |
| 54 | public: |
| 55 | explicit ConnectServiceLoader(const ViewManager::RootCallback& callback) |
| 56 | : callback_(callback) {} |
| 57 | virtual ~ConnectServiceLoader() {} |
| 58 | |
| 59 | private: |
| 60 | // Overridden from ServiceLoader: |
| 61 | virtual void LoadService(ServiceManager* manager, |
| 62 | const GURL& url, |
| 63 | ScopedMessagePipeHandle shell_handle) OVERRIDE { |
| 64 | scoped_ptr<Application> app(new Application(shell_handle.Pass())); |
| 65 | // TODO(beng): test removed callback. |
| 66 | ViewManager::Create(app.get(), callback_, ViewManager::RootCallback()); |
| 67 | apps_.push_back(app.release()); |
| 68 | } |
| 69 | virtual void OnServiceError(ServiceManager* manager, |
| 70 | const GURL& url) OVERRIDE { |
| 71 | } |
| 72 | |
| 73 | ScopedVector<Application> apps_; |
| 74 | ViewManager::RootCallback callback_; |
| 75 | |
| 76 | DISALLOW_COPY_AND_ASSIGN(ConnectServiceLoader); |
| 77 | }; |
| 78 | |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 79 | class ActiveViewChangedObserver : public ViewTreeNodeObserver { |
| 80 | public: |
| 81 | explicit ActiveViewChangedObserver(ViewTreeNode* node) |
| 82 | : node_(node) {} |
| 83 | virtual ~ActiveViewChangedObserver() {} |
| 84 | |
| 85 | private: |
| 86 | // Overridden from ViewTreeNodeObserver: |
| 87 | virtual void OnNodeActiveViewChange(ViewTreeNode* node, |
| 88 | View* old_view, |
| 89 | View* new_view, |
| 90 | DispositionChangePhase phase) OVERRIDE { |
| 91 | DCHECK_EQ(node, node_); |
| 92 | QuitRunLoop(); |
| 93 | } |
| 94 | |
| 95 | ViewTreeNode* node_; |
| 96 | |
| 97 | DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedObserver); |
| 98 | }; |
| 99 | |
| 100 | // Waits until the active view id of the supplied node changes. |
| 101 | void WaitForActiveViewToChange(ViewTreeNode* node) { |
| 102 | ActiveViewChangedObserver observer(node); |
| 103 | node->AddObserver(&observer); |
| 104 | DoRunLoop(); |
| 105 | node->RemoveObserver(&observer); |
| 106 | } |
| 107 | |
| 108 | class BoundsChangeObserver : public ViewTreeNodeObserver { |
| 109 | public: |
| 110 | explicit BoundsChangeObserver(ViewTreeNode* node) : node_(node) {} |
| 111 | virtual ~BoundsChangeObserver() {} |
| 112 | |
| 113 | private: |
| 114 | // Overridden from ViewTreeNodeObserver: |
| 115 | virtual void OnNodeBoundsChange(ViewTreeNode* node, |
| 116 | const gfx::Rect& old_bounds, |
| 117 | const gfx::Rect& new_bounds, |
| 118 | DispositionChangePhase phase) OVERRIDE { |
| 119 | DCHECK_EQ(node, node_); |
| 120 | if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 121 | return; |
| 122 | QuitRunLoop(); |
| 123 | } |
| 124 | |
| 125 | ViewTreeNode* node_; |
| 126 | |
| 127 | DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); |
| 128 | }; |
| 129 | |
| 130 | // Wait until the bounds of the supplied node change. |
| 131 | void WaitForBoundsToChange(ViewTreeNode* node) { |
| 132 | BoundsChangeObserver observer(node); |
| 133 | node->AddObserver(&observer); |
| 134 | DoRunLoop(); |
| 135 | node->RemoveObserver(&observer); |
| 136 | } |
| 137 | |
| 138 | // Spins a runloop until the tree beginning at |root| has |tree_size| nodes |
| 139 | // (including |root|). |
| 140 | class TreeSizeMatchesObserver : public ViewTreeNodeObserver { |
| 141 | public: |
| 142 | TreeSizeMatchesObserver(ViewTreeNode* tree, size_t tree_size) |
| 143 | : tree_(tree), |
| 144 | tree_size_(tree_size) {} |
| 145 | virtual ~TreeSizeMatchesObserver() {} |
| 146 | |
| 147 | bool IsTreeCorrectSize() { |
| 148 | return CountNodes(tree_) == tree_size_; |
| 149 | } |
| 150 | |
| 151 | private: |
| 152 | // Overridden from ViewTreeNodeObserver: |
| 153 | virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE { |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 154 | if (IsTreeCorrectSize()) |
| 155 | QuitRunLoop(); |
| 156 | } |
| 157 | |
| 158 | size_t CountNodes(const ViewTreeNode* node) const { |
| 159 | size_t count = 1; |
| 160 | ViewTreeNode::Children::const_iterator it = node->children().begin(); |
| 161 | for (; it != node->children().end(); ++it) |
| 162 | count += CountNodes(*it); |
| 163 | return count; |
| 164 | } |
| 165 | |
| 166 | ViewTreeNode* tree_; |
| 167 | size_t tree_size_; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 168 | |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 169 | DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); |
| 170 | }; |
| 171 | |
| 172 | void WaitForTreeSizeToMatch(ViewTreeNode* node, size_t tree_size) { |
| 173 | TreeSizeMatchesObserver observer(node, tree_size); |
| 174 | if (observer.IsTreeCorrectSize()) |
| 175 | return; |
| 176 | node->AddObserver(&observer); |
| 177 | DoRunLoop(); |
| 178 | node->RemoveObserver(&observer); |
| 179 | } |
| 180 | |
| 181 | |
| 182 | // Utility class that waits for the destruction of some number of nodes and |
| 183 | // views. |
| 184 | class DestructionObserver : public ViewTreeNodeObserver, |
| 185 | public ViewObserver { |
| 186 | public: |
| 187 | // |nodes| or |views| can be NULL. |
| 188 | DestructionObserver(std::set<TransportNodeId>* nodes, |
| 189 | std::set<TransportViewId>* views) |
| 190 | : nodes_(nodes), |
| 191 | views_(views) {} |
| 192 | |
| 193 | private: |
| 194 | // Overridden from ViewTreeNodeObserver: |
| 195 | virtual void OnNodeDestroy( |
| 196 | ViewTreeNode* node, |
| 197 | ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE { |
| 198 | if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 199 | return; |
| 200 | std::set<TransportNodeId>::const_iterator it = nodes_->find(node->id()); |
| 201 | if (it != nodes_->end()) |
| 202 | nodes_->erase(it); |
| 203 | if (CanQuit()) |
| 204 | QuitRunLoop(); |
| 205 | } |
| 206 | |
| 207 | // Overridden from ViewObserver: |
| 208 | virtual void OnViewDestroy( |
| 209 | View* view, |
| 210 | ViewObserver::DispositionChangePhase phase) OVERRIDE { |
| 211 | if (phase != ViewObserver::DISPOSITION_CHANGED) |
| 212 | return; |
| 213 | std::set<TransportViewId>::const_iterator it = views_->find(view->id()); |
| 214 | if (it != views_->end()) |
| 215 | views_->erase(it); |
| 216 | if (CanQuit()) |
| 217 | QuitRunLoop(); |
| 218 | } |
| 219 | |
| 220 | bool CanQuit() { |
| 221 | return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty()); |
| 222 | } |
| 223 | |
| 224 | std::set<TransportNodeId>* nodes_; |
| 225 | std::set<TransportViewId>* views_; |
| 226 | |
| 227 | DISALLOW_COPY_AND_ASSIGN(DestructionObserver); |
| 228 | }; |
| 229 | |
| 230 | void WaitForDestruction(ViewManager* view_manager, |
| 231 | std::set<TransportNodeId>* nodes, |
| 232 | std::set<TransportViewId>* views) { |
| 233 | DestructionObserver observer(nodes, views); |
| 234 | DCHECK(nodes || views); |
| 235 | if (nodes) { |
| 236 | for (std::set<TransportNodeId>::const_iterator it = nodes->begin(); |
| 237 | it != nodes->end(); ++it) { |
| 238 | view_manager->GetNodeById(*it)->AddObserver(&observer); |
| 239 | } |
| 240 | } |
| 241 | if (views) { |
| 242 | for (std::set<TransportViewId>::const_iterator it = views->begin(); |
| 243 | it != views->end(); ++it) { |
| 244 | view_manager->GetViewById(*it)->AddObserver(&observer); |
| 245 | } |
| 246 | } |
| 247 | DoRunLoop(); |
| 248 | } |
| 249 | |
| 250 | // Tracks a node's destruction. Query is_valid() for current state. |
| 251 | class NodeTracker : public ViewTreeNodeObserver { |
| 252 | public: |
| 253 | explicit NodeTracker(ViewTreeNode* node) : node_(node) { |
| 254 | node_->AddObserver(this); |
| 255 | } |
| 256 | virtual ~NodeTracker() { |
| 257 | if (node_) |
| 258 | node_->RemoveObserver(this); |
| 259 | } |
| 260 | |
| 261 | bool is_valid() const { return !!node_; } |
| 262 | |
| 263 | private: |
| 264 | // Overridden from ViewTreeNodeObserver: |
| 265 | virtual void OnNodeDestroy( |
| 266 | ViewTreeNode* node, |
| 267 | ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE { |
| 268 | if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) |
| 269 | return; |
| 270 | DCHECK_EQ(node, node_); |
| 271 | node_ = NULL; |
| 272 | } |
| 273 | |
| 274 | int id_; |
| 275 | ViewTreeNode* node_; |
| 276 | |
| 277 | DISALLOW_COPY_AND_ASSIGN(NodeTracker); |
| 278 | }; |
| 279 | |
| 280 | } // namespace |
| 281 | |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 282 | // ViewManager ----------------------------------------------------------------- |
| 283 | |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 284 | // These tests model synchronization of two peer connections to the view manager |
| 285 | // service, that are given access to some root node. |
| 286 | |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 287 | class ViewManagerTest : public testing::Test { |
| 288 | public: |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 289 | ViewManagerTest() |
| 290 | : connect_loop_(NULL), |
| 291 | loaded_view_manager_(NULL), |
| 292 | window_manager_(NULL), |
| 293 | commit_count_(0) {} |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 294 | |
| 295 | protected: |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 296 | ViewManager* window_manager() { return window_manager_; } |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 297 | |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 298 | ViewTreeNode* CreateNodeInParent(ViewTreeNode* parent) { |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 299 | ViewManager* parent_manager = ViewTreeNodePrivate(parent).view_manager(); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 300 | ViewTreeNode* node = ViewTreeNode::Create(parent_manager); |
| 301 | parent->AddChild(node); |
| 302 | return node; |
| 303 | } |
| 304 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 305 | // Embeds another version of the test app @ node. |
| 306 | ViewManager* Embed(ViewManager* view_manager, ViewTreeNode* node) { |
| 307 | DCHECK_EQ(view_manager, ViewTreeNodePrivate(node).view_manager()); |
| 308 | node->Embed(kEmbeddedApp1URL); |
| 309 | RunRunLoop(); |
| 310 | return GetLoadedViewManager(); |
| 311 | } |
| 312 | |
| 313 | // TODO(beng): remove these methods once all the tests are migrated. |
| 314 | void DestroyViewManager1() {} |
| 315 | ViewManager* view_manager_1() { return NULL; } |
| 316 | ViewManager* view_manager_2() { return NULL; } |
| 317 | |
| 318 | ViewManager* GetLoadedViewManager() { |
| 319 | ViewManager* view_manager = loaded_view_manager_; |
| 320 | loaded_view_manager_ = NULL; |
| 321 | return view_manager; |
| 322 | } |
| 323 | |
| 324 | void UnloadApplication(const GURL& url) { |
| 325 | test_helper_.SetLoaderForURL(scoped_ptr<ServiceLoader>(), url); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 326 | } |
| 327 | |
| 328 | private: |
| 329 | // Overridden from testing::Test: |
| 330 | virtual void SetUp() OVERRIDE { |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 331 | ViewManager::RootCallback ready_callback = |
| 332 | base::Bind(&ViewManagerTest::OnViewManagerLoaded, |
| 333 | base::Unretained(this)); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 334 | test_helper_.Init(); |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 335 | test_helper_.SetLoaderForURL( |
| 336 | scoped_ptr<ServiceLoader>(new ConnectServiceLoader(ready_callback)), |
| 337 | GURL(kWindowManagerURL)); |
| 338 | test_helper_.SetLoaderForURL( |
| 339 | scoped_ptr<ServiceLoader>(new ConnectServiceLoader(ready_callback)), |
| 340 | GURL(kEmbeddedApp1URL)); |
| 341 | |
| 342 | ConnectToService(test_helper_.service_provider(), |
| 343 | "mojo:mojo_view_manager", |
| 344 | &view_manager_init_); |
| 345 | ASSERT_TRUE(ViewManagerInitConnect(view_manager_init_.get(), |
| 346 | kWindowManagerURL)); |
| 347 | } |
| 348 | |
| 349 | void ViewManagerInitConnectCallback(bool* result_cache, |
| 350 | bool result) { |
| 351 | *result_cache = result; |
| 352 | } |
| 353 | |
| 354 | bool ViewManagerInitConnect(IViewManagerInit* view_manager_init, |
| 355 | const std::string& url) { |
| 356 | bool result = false; |
| 357 | view_manager_init->Connect( |
| 358 | url, |
| 359 | base::Bind(&ViewManagerTest::ViewManagerInitConnectCallback, |
| 360 | base::Unretained(this), &result)); |
| 361 | RunRunLoop(); |
| 362 | window_manager_ = GetLoadedViewManager(); |
| 363 | return result; |
| 364 | } |
| 365 | |
| 366 | void OnViewManagerLoaded(ViewManager* view_manager, ViewTreeNode* root) { |
| 367 | loaded_view_manager_ = view_manager; |
| 368 | connect_loop_->Quit(); |
| 369 | } |
| 370 | |
| 371 | void RunRunLoop() { |
| 372 | base::RunLoop run_loop; |
| 373 | connect_loop_ = &run_loop; |
| 374 | connect_loop_->Run(); |
| 375 | connect_loop_ = NULL; |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 376 | } |
| 377 | |
| 378 | base::MessageLoop loop_; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 379 | base::RunLoop* connect_loop_; |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 380 | shell::ShellTestHelper test_helper_; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 381 | IViewManagerInitPtr view_manager_init_; |
| 382 | // Used to receive the most recent view manager loaded by an embed action. |
| 383 | ViewManager* loaded_view_manager_; |
| 384 | // The View Manager connection held by the window manager (app running at the |
| 385 | // root node). |
| 386 | ViewManager* window_manager_; |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 387 | int commit_count_; |
| 388 | |
| 389 | DISALLOW_COPY_AND_ASSIGN(ViewManagerTest); |
| 390 | }; |
| 391 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 392 | TEST_F(ViewManagerTest, SetUp) {} |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 393 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 394 | TEST_F(ViewManagerTest, Embed) { |
| 395 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 396 | window_manager()->roots().front()->AddChild(node); |
| 397 | ViewManager* embedded = Embed(window_manager(), node); |
| 398 | EXPECT_TRUE(NULL != embedded); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 399 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 400 | ViewTreeNode* node_in_embedded = embedded->roots().front(); |
| 401 | EXPECT_EQ(node->parent(), window_manager()->roots().front()); |
| 402 | EXPECT_EQ(NULL, node_in_embedded->parent()); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 403 | } |
| 404 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 405 | // When Window Manager embeds A @ N, then creates N2 and parents to N, N becomes |
| 406 | // visible to A. |
| 407 | // TODO(beng): verify whether or not this is a policy we like. |
| 408 | TEST_F(ViewManagerTest, HierarchyChanged_NodeAdded) { |
| 409 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 410 | window_manager()->roots().front()->AddChild(node); |
| 411 | ViewManager* embedded = Embed(window_manager(), node); |
| 412 | ViewTreeNode* nested = ViewTreeNode::Create(window_manager()); |
| 413 | node->AddChild(nested); |
| 414 | WaitForTreeSizeToMatch(embedded->roots().front(), 2); |
| 415 | EXPECT_EQ(embedded->roots().front()->children().front()->id(), nested->id()); |
| 416 | } |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 417 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 418 | // Window manager has two nodes, N1 & N2. Embeds A at N1. Creates node N21, |
| 419 | // a child of N2. Reparents N2 to N1. N1 should become visible to A. |
| 420 | // TODO(beng): verify whether or not this is a policy we like. |
| 421 | TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) { |
| 422 | ViewTreeNode* node1 = ViewTreeNode::Create(window_manager()); |
| 423 | window_manager()->roots().front()->AddChild(node1); |
| 424 | ViewManager* embedded = Embed(window_manager(), node1); |
| 425 | WaitForTreeSizeToMatch(embedded->roots().front(), 1); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 426 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 427 | ViewTreeNode* node2 = ViewTreeNode::Create(window_manager()); |
| 428 | window_manager()->roots().front()->AddChild(node2); |
| 429 | WaitForTreeSizeToMatch(embedded->roots().front(), 1); |
| 430 | EXPECT_TRUE(embedded->roots().front()->children().empty()); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 431 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 432 | ViewTreeNode* node21 = ViewTreeNode::Create(window_manager()); |
| 433 | node2->AddChild(node21); |
| 434 | WaitForTreeSizeToMatch(embedded->roots().front(), 1); |
| 435 | EXPECT_TRUE(embedded->roots().front()->children().empty()); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 436 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 437 | // Makes node21 visible to |embedded|. |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 438 | node1->AddChild(node21); |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 439 | WaitForTreeSizeToMatch(embedded->roots().front(), 2); |
| 440 | EXPECT_FALSE(embedded->roots().front()->children().empty()); |
| 441 | EXPECT_EQ(embedded->roots().front()->children().front()->id(), node21->id()); |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 442 | } |
| 443 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 444 | // Window manager has two nodes, N1 and N11. Embeds A at N1. Removes N11 from |
| 445 | // N1. N11 should disappear from A. |
| 446 | // TODO(beng): verify whether or not this is a policy we like. |
| 447 | TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) { |
| 448 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 449 | window_manager()->roots().front()->AddChild(node); |
| 450 | ViewTreeNode* nested = ViewTreeNode::Create(window_manager()); |
| 451 | node->AddChild(nested); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 452 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 453 | ViewManager* embedded = Embed(window_manager(), node); |
| 454 | EXPECT_EQ(embedded->roots().front()->children().front()->id(), nested->id()); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 455 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 456 | node->RemoveChild(nested); |
| 457 | WaitForTreeSizeToMatch(embedded->roots().front(), 1); |
| 458 | EXPECT_TRUE(embedded->roots().front()->children().empty()); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 459 | } |
| 460 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 461 | // Window manager has two nodes, N1 and N11. Embeds A at N1. Destroys N11. |
| 462 | // N11 should disappear from A. |
| 463 | // TODO(beng): verify whether or not this is a policy we like. |
| 464 | TEST_F(ViewManagerTest, NodeDestroyed) { |
| 465 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 466 | window_manager()->roots().front()->AddChild(node); |
| 467 | ViewTreeNode* nested = ViewTreeNode::Create(window_manager()); |
| 468 | node->AddChild(nested); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 469 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 470 | ViewManager* embedded = Embed(window_manager(), node); |
| 471 | EXPECT_EQ(embedded->roots().front()->children().front()->id(), nested->id()); |
| 472 | |
| 473 | // |nested| will be deleted after calling Destroy() below. |
| 474 | TransportNodeId id = nested->id(); |
| 475 | nested->Destroy(); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 476 | |
| 477 | std::set<TransportNodeId> nodes; |
| 478 | nodes.insert(id); |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 479 | WaitForDestruction(embedded, &nodes, NULL); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 480 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 481 | EXPECT_TRUE(embedded->roots().front()->children().empty()); |
| 482 | EXPECT_EQ(NULL, embedded->GetNodeById(id)); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 483 | } |
| 484 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 485 | TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) { |
| 486 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 487 | window_manager()->roots().front()->AddChild(node); |
| 488 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 489 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 490 | TransportNodeId node_id = node->id(); |
| 491 | |
| 492 | UnloadApplication(GURL(kWindowManagerURL)); |
| 493 | |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 494 | std::set<TransportNodeId> nodes; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 495 | nodes.insert(node_id); |
| 496 | WaitForDestruction(embedded, &nodes, NULL); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 497 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 498 | EXPECT_TRUE(embedded->roots().empty()); |
Torne (Richard Coles) | 0de6073 | 2014-05-15 12:16:31 +0100 | [diff] [blame] | 499 | } |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 500 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 501 | TEST_F(ViewManagerTest, SetActiveView) { |
| 502 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 503 | window_manager()->roots().front()->AddChild(node); |
| 504 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 505 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 506 | View* view = View::Create(window_manager()); |
| 507 | node->SetActiveView(view); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 508 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 509 | ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 510 | WaitForActiveViewToChange(node_in_embedded); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 511 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 512 | EXPECT_EQ(node_in_embedded->active_view()->id(), view->id()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 513 | } |
| 514 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 515 | TEST_F(ViewManagerTest, DestroyView) { |
| 516 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 517 | window_manager()->roots().front()->AddChild(node); |
| 518 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 519 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 520 | View* view = View::Create(window_manager()); |
| 521 | node->SetActiveView(view); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 522 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 523 | ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 524 | WaitForActiveViewToChange(node_in_embedded); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 525 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 526 | EXPECT_EQ(node_in_embedded->active_view()->id(), view->id()); |
| 527 | |
| 528 | TransportViewId view_id = view->id(); |
| 529 | view->Destroy(); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 530 | |
| 531 | std::set<TransportViewId> views; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 532 | views.insert(view_id); |
| 533 | WaitForDestruction(embedded, NULL, &views); |
| 534 | EXPECT_EQ(NULL, node_in_embedded->active_view()); |
| 535 | EXPECT_EQ(NULL, embedded->GetViewById(view_id)); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 536 | } |
| 537 | |
| 538 | // Destroying the connection that created a node and view should result in that |
| 539 | // node and view disappearing from all connections that see them. |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 540 | TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) { |
| 541 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 542 | window_manager()->roots().front()->AddChild(node); |
| 543 | View* view = View::Create(window_manager()); |
| 544 | node->SetActiveView(view); |
| 545 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 546 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 547 | TransportNodeId node_id = node->id(); |
| 548 | TransportViewId view_id = view->id(); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 549 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 550 | UnloadApplication(GURL(kWindowManagerURL)); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 551 | |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 552 | std::set<TransportNodeId> observed_nodes; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 553 | observed_nodes.insert(node_id); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 554 | std::set<TransportViewId> observed_views; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 555 | observed_views.insert(view_id); |
| 556 | WaitForDestruction(embedded, &observed_nodes, &observed_views); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 557 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 558 | EXPECT_TRUE(embedded->roots().empty()); |
| 559 | EXPECT_EQ(NULL, embedded->GetNodeById(node_id)); |
| 560 | EXPECT_EQ(NULL, embedded->GetViewById(view_id)); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 561 | } |
| 562 | |
| 563 | // This test validates the following scenario: |
| 564 | // - a node originating from one connection |
| 565 | // - a view originating from a second connection |
| 566 | // + the connection originating the node is destroyed |
| 567 | // -> the view should still exist (since the second connection is live) but |
| 568 | // should be disconnected from any nodes. |
| 569 | TEST_F(ViewManagerTest, |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 570 | ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) { |
| 571 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 572 | window_manager()->roots().front()->AddChild(node); |
| 573 | ViewManager* embedded = Embed(window_manager(), node); |
| 574 | View* view_in_embedded = View::Create(embedded); |
| 575 | ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 576 | node_in_embedded->SetActiveView(view_in_embedded); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 577 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 578 | WaitForActiveViewToChange(node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 579 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 580 | TransportNodeId node_id = node->id(); |
| 581 | TransportViewId view_id = view_in_embedded->id(); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 582 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 583 | UnloadApplication(GURL(kWindowManagerURL)); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 584 | std::set<TransportNodeId> nodes; |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 585 | nodes.insert(node_id); |
| 586 | WaitForDestruction(embedded, &nodes, NULL); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 587 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 588 | EXPECT_TRUE(embedded->roots().empty()); |
| 589 | // node was owned by the window manager, so it should be gone. |
| 590 | EXPECT_EQ(NULL, embedded->GetNodeById(node_id)); |
| 591 | // view_in_embedded was owned by the embedded app, so it should still exist, |
| 592 | // but disconnected from the node tree. |
| 593 | EXPECT_EQ(view_in_embedded, embedded->GetViewById(view_id)); |
| 594 | EXPECT_EQ(NULL, view_in_embedded->node()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 595 | } |
| 596 | |
| 597 | // This test verifies that it is not possible to set the active view to a view |
| 598 | // defined in a different connection. |
| 599 | // TODO(beng): write these tests for ViewTreeNode::AddChild(), RemoveChild() and |
| 600 | // Contains(). |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 601 | TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { |
| 602 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 603 | window_manager()->roots().front()->AddChild(node); |
| 604 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 605 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 606 | View* view_in_embedded = View::Create(embedded); |
| 607 | EXPECT_DEATH(node->SetActiveView(view_in_embedded), ""); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 608 | } |
| 609 | |
| 610 | // This test verifies that a node hierarchy constructed in one connection |
| 611 | // becomes entirely visible to the second connection when the hierarchy is |
| 612 | // attached. |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 613 | TEST_F(ViewManagerTest, MapSubtreeOnAttach) { |
| 614 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 615 | window_manager()->roots().front()->AddChild(node); |
| 616 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 617 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 618 | // Create a subtree private to the window manager and make some changes to it. |
| 619 | ViewTreeNode* child1 = ViewTreeNode::Create(window_manager()); |
| 620 | ViewTreeNode* child11 = ViewTreeNode::Create(window_manager()); |
| 621 | child1->AddChild(child11); |
| 622 | gfx::Rect child11_bounds(800, 600); |
| 623 | child11->SetBounds(child11_bounds); |
| 624 | View* view11 = View::Create(window_manager()); |
| 625 | child11->SetActiveView(view11); |
| 626 | WaitForAllChangesToBeAcked(window_manager()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 627 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 628 | // When added to the shared node, the entire hierarchy and all property |
| 629 | // changes should become visible to the embedded app. |
| 630 | node->AddChild(child1); |
| 631 | WaitForTreeSizeToMatch(embedded->roots().front(), 3); |
| 632 | |
| 633 | ViewTreeNode* child11_in_embedded = embedded->GetNodeById(child11->id()); |
| 634 | View* view11_in_embedded = embedded->GetViewById(view11->id()); |
| 635 | EXPECT_TRUE(child11_in_embedded != NULL); |
| 636 | EXPECT_EQ(view11_in_embedded, child11_in_embedded->active_view()); |
| 637 | EXPECT_EQ(child11_bounds, child11_in_embedded->bounds()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 638 | } |
| 639 | |
| 640 | // Verifies that bounds changes applied to a node hierarchy in one connection |
| 641 | // are reflected to another. |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 642 | TEST_F(ViewManagerTest, SetBounds) { |
| 643 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 644 | window_manager()->roots().front()->AddChild(node); |
| 645 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 646 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 647 | ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 648 | EXPECT_EQ(node->bounds(), node_in_embedded->bounds()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 649 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 650 | node->SetBounds(gfx::Rect(100, 100)); |
| 651 | EXPECT_NE(node->bounds(), node_in_embedded->bounds()); |
| 652 | WaitForBoundsToChange(node_in_embedded); |
| 653 | EXPECT_EQ(node->bounds(), node_in_embedded->bounds()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 654 | } |
| 655 | |
| 656 | // Verifies that bounds changes applied to a node owned by a different |
| 657 | // connection are refused. |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 658 | TEST_F(ViewManagerTest, SetBoundsSecurity) { |
| 659 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 660 | window_manager()->roots().front()->AddChild(node); |
| 661 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 662 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 663 | ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 664 | node->SetBounds(gfx::Rect(800, 600)); |
| 665 | WaitForBoundsToChange(node_in_embedded); |
| 666 | |
| 667 | node_in_embedded->SetBounds(gfx::Rect(1024, 768)); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 668 | // Bounds change should have been rejected. |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 669 | EXPECT_EQ(node->bounds(), node_in_embedded->bounds()); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 670 | } |
| 671 | |
| 672 | // Verifies that a node can only be destroyed by the connection that created it. |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 673 | TEST_F(ViewManagerTest, DestroySecurity) { |
| 674 | ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 675 | window_manager()->roots().front()->AddChild(node); |
| 676 | ViewManager* embedded = Embed(window_manager(), node); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 677 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 678 | ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 679 | |
| 680 | NodeTracker tracker2(node_in_embedded); |
| 681 | node_in_embedded->Destroy(); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 682 | // Node should not have been destroyed. |
| 683 | EXPECT_TRUE(tracker2.is_valid()); |
| 684 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 685 | NodeTracker tracker1(node); |
| 686 | node->Destroy(); |
Torne (Richard Coles) | cedac22 | 2014-06-03 10:58:34 +0100 | [diff] [blame] | 687 | EXPECT_FALSE(tracker1.is_valid()); |
| 688 | } |
| 689 | |
Torne (Richard Coles) | 46d4c2b | 2014-06-09 12:00:27 +0100 | [diff] [blame^] | 690 | TEST_F(ViewManagerTest, MultiRoots) { |
| 691 | ViewTreeNode* node1 = ViewTreeNode::Create(window_manager()); |
| 692 | window_manager()->roots().front()->AddChild(node1); |
| 693 | ViewTreeNode* node2 = ViewTreeNode::Create(window_manager()); |
| 694 | window_manager()->roots().front()->AddChild(node2); |
| 695 | ViewManager* embedded1 = Embed(window_manager(), node1); |
| 696 | ViewManager* embedded2 = Embed(window_manager(), node2); |
| 697 | EXPECT_EQ(embedded1, embedded2); |
| 698 | } |
| 699 | |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 700 | } // namespace view_manager |
Torne (Richard Coles) | 010d83a | 2014-05-14 12:12:37 +0100 | [diff] [blame] | 701 | } // namespace mojo |