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 <string> 6 #include <vector> 7 8 #include "base/at_exit.h" 9 #include "base/auto_reset.h" 10 #include "base/bind.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_vector.h" 13 #include "base/message_loop/message_loop.h" 14 #include "base/run_loop.h" 15 #include "base/strings/stringprintf.h" 16 #include "mojo/application_manager/application_manager.h" 17 #include "mojo/common/common_type_converters.h" 18 #include "mojo/public/cpp/application/application_connection.h" 19 #include "mojo/public/cpp/application/application_delegate.h" 20 #include "mojo/public/cpp/application/application_impl.h" 21 #include "mojo/public/cpp/application/connect.h" 22 #include "mojo/public/cpp/bindings/lib/router.h" 23 #include "mojo/public/interfaces/application/service_provider.mojom.h" 24 #include "mojo/services/public/cpp/geometry/geometry_type_converters.h" 25 #include "mojo/services/public/cpp/view_manager/types.h" 26 #include "mojo/services/public/cpp/view_manager/util.h" 27 #include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h" 28 #include "mojo/services/view_manager/ids.h" 29 #include "mojo/services/view_manager/test_change_tracker.h" 30 #include "mojo/shell/shell_test_helper.h" 31 #include "testing/gtest/include/gtest/gtest.h" 32 #include "ui/gfx/geometry/rect.h" 33 34 #if defined(OS_WIN) 35 #include "ui/gfx/win/window_impl.h" 36 #endif 37 38 namespace mojo { 39 namespace service { 40 41 namespace { 42 43 const char kTestServiceURL[] = "mojo:test_url"; 44 const char kTestServiceURL2[] = "mojo:test_url2"; 45 46 // ViewManagerProxy is a proxy to an ViewManagerService. It handles invoking 47 // ViewManagerService functions on the right thread in a synchronous manner 48 // (each ViewManagerService cover function blocks until the response from the 49 // ViewManagerService is returned). In addition it tracks the set of 50 // ViewManagerClient messages received by way of a vector of Changes. Use 51 // DoRunLoopUntilChangesCount() to wait for a certain number of messages to be 52 // received. 53 class ViewManagerProxy : public TestChangeTracker::Delegate { 54 public: 55 explicit ViewManagerProxy(TestChangeTracker* tracker) 56 : tracker_(tracker), 57 main_loop_(NULL), 58 view_manager_(NULL), 59 quit_count_(0), 60 router_(NULL) { 61 SetInstance(this); 62 } 63 64 virtual ~ViewManagerProxy() { 65 } 66 67 // Returns true if in an initial state. If this returns false it means the 68 // last test didn't clean up properly, or most likely didn't invoke 69 // WaitForInstance() when it needed to. 70 static bool IsInInitialState() { return instance_ == NULL; } 71 72 // Runs a message loop until the single instance has been created. 73 static ViewManagerProxy* WaitForInstance() { 74 if (!instance_) 75 RunMainLoop(); 76 ViewManagerProxy* instance = instance_; 77 instance_ = NULL; 78 return instance; 79 } 80 81 ViewManagerService* view_manager() { return view_manager_; } 82 83 // Runs the main loop until |count| changes have been received. 84 std::vector<Change> DoRunLoopUntilChangesCount(size_t count) { 85 DCHECK_EQ(0u, quit_count_); 86 if (tracker_->changes()->size() >= count) { 87 CopyChangesFromTracker(); 88 return changes_; 89 } 90 quit_count_ = count - tracker_->changes()->size(); 91 // Run the current message loop. When |count| Changes have been received, 92 // we'll quit. 93 RunMainLoop(); 94 return changes_; 95 } 96 97 const std::vector<Change>& changes() const { return changes_; } 98 99 // Destroys the connection, blocking until done. 100 void Destroy() { 101 router_->CloseMessagePipe(); 102 } 103 104 void ClearChanges() { 105 changes_.clear(); 106 tracker_->changes()->clear(); 107 } 108 109 void CopyChangesFromTracker() { 110 std::vector<Change> changes; 111 tracker_->changes()->swap(changes); 112 changes_.swap(changes); 113 } 114 115 // The following functions are cover methods for ViewManagerService. They 116 // block until the result is received. 117 bool CreateView(Id view_id) { 118 changes_.clear(); 119 ErrorCode result = ERROR_CODE_NONE; 120 view_manager_->CreateView( 121 view_id, 122 base::Bind(&ViewManagerProxy::GotResultWithErrorCode, 123 base::Unretained(this), 124 &result)); 125 RunMainLoop(); 126 return result == ERROR_CODE_NONE; 127 } 128 ErrorCode CreateViewWithErrorCode(Id view_id) { 129 changes_.clear(); 130 ErrorCode result = ERROR_CODE_NONE; 131 view_manager_->CreateView( 132 view_id, 133 base::Bind(&ViewManagerProxy::GotResultWithErrorCode, 134 base::Unretained(this), 135 &result)); 136 RunMainLoop(); 137 return result; 138 } 139 bool AddView(Id parent, Id child) { 140 changes_.clear(); 141 bool result = false; 142 view_manager_->AddView(parent, child, 143 base::Bind(&ViewManagerProxy::GotResult, 144 base::Unretained(this), &result)); 145 RunMainLoop(); 146 return result; 147 } 148 bool RemoveViewFromParent(Id view_id) { 149 changes_.clear(); 150 bool result = false; 151 view_manager_->RemoveViewFromParent( 152 view_id, 153 base::Bind( 154 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); 155 RunMainLoop(); 156 return result; 157 } 158 bool ReorderView(Id view_id, Id relative_view_id, OrderDirection direction) { 159 changes_.clear(); 160 bool result = false; 161 view_manager_->ReorderView( 162 view_id, 163 relative_view_id, 164 direction, 165 base::Bind( 166 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); 167 RunMainLoop(); 168 return result; 169 } 170 void GetViewTree(Id view_id, std::vector<TestView>* views) { 171 changes_.clear(); 172 view_manager_->GetViewTree( 173 view_id, 174 base::Bind( 175 &ViewManagerProxy::GotViewTree, base::Unretained(this), views)); 176 RunMainLoop(); 177 } 178 bool Embed(const Id view_id, const char* url) { 179 changes_.clear(); 180 base::AutoReset<bool> auto_reset(&in_embed_, true); 181 bool result = false; 182 ServiceProviderPtr services; 183 view_manager_->Embed( 184 url, 185 view_id, 186 services.Pass(), 187 base::Bind( 188 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); 189 RunMainLoop(); 190 return result; 191 } 192 bool DeleteView(Id view_id) { 193 changes_.clear(); 194 bool result = false; 195 view_manager_->DeleteView( 196 view_id, 197 base::Bind( 198 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); 199 RunMainLoop(); 200 return result; 201 } 202 bool SetViewBounds(Id view_id, const gfx::Rect& bounds) { 203 changes_.clear(); 204 bool result = false; 205 view_manager_->SetViewBounds( 206 view_id, 207 Rect::From(bounds), 208 base::Bind( 209 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); 210 RunMainLoop(); 211 return result; 212 } 213 bool SetViewVisibility(Id view_id, bool visible) { 214 changes_.clear(); 215 bool result = false; 216 view_manager_->SetViewVisibility( 217 view_id, 218 visible, 219 base::Bind( 220 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); 221 RunMainLoop(); 222 return result; 223 } 224 225 private: 226 friend class TestViewManagerClientConnection; 227 228 void set_router(mojo::internal::Router* router) { router_ = router; } 229 230 void set_view_manager(ViewManagerService* view_manager) { 231 view_manager_ = view_manager; 232 } 233 234 static void RunMainLoop() { 235 DCHECK(!main_run_loop_); 236 main_run_loop_ = new base::RunLoop; 237 main_run_loop_->Run(); 238 delete main_run_loop_; 239 main_run_loop_ = NULL; 240 } 241 242 void QuitCountReached() { 243 CopyChangesFromTracker(); 244 main_run_loop_->Quit(); 245 } 246 247 static void SetInstance(ViewManagerProxy* instance) { 248 DCHECK(!instance_); 249 instance_ = instance; 250 // Embed() runs its own run loop that is quit when the result is 251 // received. Embed() also results in a new instance. If we quit here while 252 // waiting for a Embed() we would prematurely return before we got the 253 // result from Embed(). 254 if (!in_embed_ && main_run_loop_) 255 main_run_loop_->Quit(); 256 } 257 258 // Callbacks from the various ViewManagerService functions. 259 void GotResult(bool* result_cache, bool result) { 260 *result_cache = result; 261 DCHECK(main_run_loop_); 262 main_run_loop_->Quit(); 263 } 264 265 void GotResultWithErrorCode(ErrorCode* error_code_cache, 266 ErrorCode error_code) { 267 *error_code_cache = error_code; 268 DCHECK(main_run_loop_); 269 main_run_loop_->Quit(); 270 } 271 272 void GotViewTree(std::vector<TestView>* views, Array<ViewDataPtr> results) { 273 ViewDatasToTestViews(results, views); 274 DCHECK(main_run_loop_); 275 main_run_loop_->Quit(); 276 } 277 278 // TestChangeTracker::Delegate: 279 virtual void OnChangeAdded() OVERRIDE { 280 if (quit_count_ > 0 && --quit_count_ == 0) 281 QuitCountReached(); 282 } 283 284 static ViewManagerProxy* instance_; 285 static base::RunLoop* main_run_loop_; 286 static bool in_embed_; 287 288 TestChangeTracker* tracker_; 289 290 // MessageLoop of the test. 291 base::MessageLoop* main_loop_; 292 293 ViewManagerService* view_manager_; 294 295 // Number of changes we're waiting on until we quit the current loop. 296 size_t quit_count_; 297 298 std::vector<Change> changes_; 299 300 mojo::internal::Router* router_; 301 302 DISALLOW_COPY_AND_ASSIGN(ViewManagerProxy); 303 }; 304 305 // static 306 ViewManagerProxy* ViewManagerProxy::instance_ = NULL; 307 308 // static 309 base::RunLoop* ViewManagerProxy::main_run_loop_ = NULL; 310 311 // static 312 bool ViewManagerProxy::in_embed_ = false; 313 314 class TestViewManagerClientConnection 315 : public InterfaceImpl<ViewManagerClient> { 316 public: 317 TestViewManagerClientConnection() : connection_(&tracker_) { 318 tracker_.set_delegate(&connection_); 319 } 320 321 // InterfaceImpl: 322 virtual void OnConnectionEstablished() OVERRIDE { 323 connection_.set_router(internal_state()->router()); 324 connection_.set_view_manager(client()); 325 } 326 327 // ViewManagerClient: 328 virtual void OnEmbed( 329 ConnectionSpecificId connection_id, 330 const String& creator_url, 331 ViewDataPtr root, 332 InterfaceRequest<ServiceProvider> services) OVERRIDE { 333 tracker_.OnEmbed(connection_id, creator_url, root.Pass()); 334 } 335 virtual void OnViewBoundsChanged(Id view_id, 336 RectPtr old_bounds, 337 RectPtr new_bounds) OVERRIDE { 338 tracker_.OnViewBoundsChanged(view_id, old_bounds.Pass(), new_bounds.Pass()); 339 } 340 virtual void OnViewHierarchyChanged(Id view, 341 Id new_parent, 342 Id old_parent, 343 Array<ViewDataPtr> views) OVERRIDE { 344 tracker_.OnViewHierarchyChanged(view, new_parent, old_parent, views.Pass()); 345 } 346 virtual void OnViewReordered(Id view_id, 347 Id relative_view_id, 348 OrderDirection direction) OVERRIDE { 349 tracker_.OnViewReordered(view_id, relative_view_id, direction); 350 } 351 virtual void OnViewDeleted(Id view) OVERRIDE { tracker_.OnViewDeleted(view); } 352 virtual void OnViewVisibilityChanged(uint32_t view, bool visible) OVERRIDE { 353 tracker_.OnViewVisibilityChanged(view, visible); 354 } 355 virtual void OnViewDrawnStateChanged(uint32_t view, bool drawn) OVERRIDE { 356 tracker_.OnViewDrawnStateChanged(view, drawn); 357 } 358 virtual void OnViewInputEvent(Id view_id, 359 EventPtr event, 360 const Callback<void()>& callback) OVERRIDE { 361 tracker_.OnViewInputEvent(view_id, event.Pass()); 362 } 363 virtual void Embed( 364 const String& url, 365 InterfaceRequest<ServiceProvider> service_provider) OVERRIDE { 366 tracker_.DelegateEmbed(url); 367 } 368 virtual void DispatchOnViewInputEvent(mojo::EventPtr event) OVERRIDE { 369 } 370 371 private: 372 TestChangeTracker tracker_; 373 ViewManagerProxy connection_; 374 375 DISALLOW_COPY_AND_ASSIGN(TestViewManagerClientConnection); 376 }; 377 378 // Used with ViewManagerService::Embed(). Creates a 379 // TestViewManagerClientConnection, which creates and owns the ViewManagerProxy. 380 class EmbedApplicationLoader : public ApplicationLoader, 381 ApplicationDelegate, 382 public InterfaceFactory<ViewManagerClient> { 383 public: 384 EmbedApplicationLoader() {} 385 virtual ~EmbedApplicationLoader() {} 386 387 // ApplicationLoader implementation: 388 virtual void Load(ApplicationManager* manager, 389 const GURL& url, 390 scoped_refptr<LoadCallbacks> callbacks) OVERRIDE { 391 ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); 392 if (!shell_handle.is_valid()) 393 return; 394 scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this, 395 shell_handle.Pass())); 396 apps_.push_back(app.release()); 397 } 398 virtual void OnApplicationError(ApplicationManager* manager, 399 const GURL& url) OVERRIDE {} 400 401 // ApplicationDelegate implementation: 402 virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) 403 OVERRIDE { 404 connection->AddService(this); 405 return true; 406 } 407 408 // InterfaceFactory<ViewManagerClient> implementation: 409 virtual void Create(ApplicationConnection* connection, 410 InterfaceRequest<ViewManagerClient> request) OVERRIDE { 411 BindToRequest(new TestViewManagerClientConnection, &request); 412 } 413 414 private: 415 ScopedVector<ApplicationImpl> apps_; 416 417 DISALLOW_COPY_AND_ASSIGN(EmbedApplicationLoader); 418 }; 419 420 // Creates an id used for transport from the specified parameters. 421 Id BuildViewId(ConnectionSpecificId connection_id, 422 ConnectionSpecificId view_id) { 423 return (connection_id << 16) | view_id; 424 } 425 426 // Callback from Embed(). |result| is the result of the 427 // Embed() call and |run_loop| the nested RunLoop. 428 void EmbedCallback(bool* result_cache, base::RunLoop* run_loop, bool result) { 429 *result_cache = result; 430 run_loop->Quit(); 431 } 432 433 // Embed from an application that does not yet have a view manager connection. 434 // Blocks until result is determined. 435 bool InitEmbed(ViewManagerInitService* view_manager_init, 436 const std::string& url, 437 size_t number_of_calls) { 438 bool result = false; 439 base::RunLoop run_loop; 440 for (size_t i = 0; i < number_of_calls; ++i) { 441 ServiceProviderPtr sp; 442 view_manager_init->Embed(url, sp.Pass(), 443 base::Bind(&EmbedCallback, &result, &run_loop)); 444 } 445 run_loop.Run(); 446 return result; 447 } 448 449 } // namespace 450 451 typedef std::vector<std::string> Changes; 452 453 class ViewManagerTest : public testing::Test { 454 public: 455 ViewManagerTest() 456 : connection_(NULL), 457 connection2_(NULL), 458 connection3_(NULL) {} 459 460 virtual void SetUp() OVERRIDE { 461 ASSERT_TRUE(ViewManagerProxy::IsInInitialState()); 462 test_helper_.Init(); 463 464 #if defined(OS_WIN) 465 // As we unload the wndproc of window classes we need to be sure to 466 // unregister them. 467 gfx::WindowImpl::UnregisterClassesAtExit(); 468 #endif 469 470 test_helper_.SetLoaderForURL( 471 scoped_ptr<ApplicationLoader>(new EmbedApplicationLoader()), 472 GURL(kTestServiceURL)); 473 474 test_helper_.SetLoaderForURL( 475 scoped_ptr<ApplicationLoader>(new EmbedApplicationLoader()), 476 GURL(kTestServiceURL2)); 477 478 test_helper_.application_manager()->ConnectToService( 479 GURL("mojo:mojo_view_manager"), &view_manager_init_); 480 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), kTestServiceURL, 1)); 481 482 connection_ = ViewManagerProxy::WaitForInstance(); 483 ASSERT_TRUE(connection_ != NULL); 484 connection_->DoRunLoopUntilChangesCount(1); 485 } 486 487 virtual void TearDown() OVERRIDE { 488 if (connection3_) 489 connection3_->Destroy(); 490 if (connection2_) 491 connection2_->Destroy(); 492 if (connection_) 493 connection_->Destroy(); 494 } 495 496 protected: 497 void EstablishSecondConnectionWithRoot(Id root_id) { 498 ASSERT_TRUE(connection_->Embed(root_id, kTestServiceURL)); 499 connection2_ = ViewManagerProxy::WaitForInstance(); 500 ASSERT_TRUE(connection2_ != NULL); 501 connection2_->DoRunLoopUntilChangesCount(1); 502 ASSERT_EQ(1u, connection2_->changes().size()); 503 } 504 505 // Creates a second connection to the viewmanager. 506 void EstablishSecondConnection(bool create_initial_view) { 507 if (create_initial_view) 508 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 509 ASSERT_NO_FATAL_FAILURE( 510 EstablishSecondConnectionWithRoot(BuildViewId(1, 1))); 511 const std::vector<Change>& changes(connection2_->changes()); 512 ASSERT_EQ(1u, changes.size()); 513 EXPECT_EQ("OnEmbed creator=mojo:test_url", 514 ChangesToDescription1(changes)[0]); 515 if (create_initial_view) 516 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes)); 517 } 518 519 void EstablishThirdConnection(ViewManagerProxy* owner, Id root_id) { 520 ASSERT_TRUE(connection3_ == NULL); 521 ASSERT_TRUE(owner->Embed(root_id, kTestServiceURL2)); 522 connection3_ = ViewManagerProxy::WaitForInstance(); 523 ASSERT_TRUE(connection3_ != NULL); 524 connection3_->DoRunLoopUntilChangesCount(1); 525 ASSERT_EQ(1u, connection3_->changes().size()); 526 EXPECT_EQ("OnEmbed creator=mojo:test_url", 527 ChangesToDescription1(connection3_->changes())[0]); 528 } 529 530 void DestroySecondConnection() { 531 connection2_->Destroy(); 532 connection2_ = NULL; 533 } 534 535 base::ShadowingAtExitManager at_exit_; 536 shell::ShellTestHelper test_helper_; 537 538 ViewManagerInitServicePtr view_manager_init_; 539 540 // NOTE: this connection is the root. As such, it has special permissions. 541 ViewManagerProxy* connection_; 542 ViewManagerProxy* connection2_; 543 ViewManagerProxy* connection3_; 544 545 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest); 546 }; 547 548 TEST_F(ViewManagerTest, SecondEmbedRoot_InitService) { 549 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), kTestServiceURL, 1)); 550 connection_->DoRunLoopUntilChangesCount(1); 551 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url); 552 } 553 554 TEST_F(ViewManagerTest, SecondEmbedRoot_Service) { 555 ASSERT_TRUE(connection_->Embed(BuildViewId(0, 0), kTestServiceURL)); 556 connection_->DoRunLoopUntilChangesCount(1); 557 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url); 558 } 559 560 TEST_F(ViewManagerTest, MultipleEmbedRootsBeforeWTHReady) { 561 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), kTestServiceURL, 2)); 562 connection_->DoRunLoopUntilChangesCount(2); 563 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url); 564 EXPECT_EQ(kTestServiceURL, connection_->changes()[1].embed_url); 565 } 566 567 // Verifies client gets a valid id. 568 // http://crbug.com/396492 569 TEST_F(ViewManagerTest, DISABLED_ValidId) { 570 // TODO(beng): this should really have the URL of the application that 571 // connected to ViewManagerInit. 572 EXPECT_EQ("OnEmbed creator=", 573 ChangesToDescription1(connection_->changes())[0]); 574 575 // All these tests assume 1 for the client id. The only real assertion here is 576 // the client id is not zero, but adding this as rest of code here assumes 1. 577 EXPECT_EQ(1, connection_->changes()[0].connection_id); 578 } 579 580 // Verifies two clients/connections get different ids. 581 TEST_F(ViewManagerTest, TwoClientsGetDifferentConnectionIds) { 582 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 583 EXPECT_EQ("OnEmbed creator=mojo:test_url", 584 ChangesToDescription1(connection2_->changes())[0]); 585 586 // It isn't strictly necessary that the second connection gets 2, but these 587 // tests are written assuming that is the case. The key thing is the 588 // connection ids of |connection_| and |connection2_| differ. 589 EXPECT_EQ(2, connection2_->changes()[0].connection_id); 590 } 591 592 // Verifies when Embed() is invoked any child views are removed. 593 TEST_F(ViewManagerTest, ViewsRemovedWhenEmbedding) { 594 // Two views 1 and 2. 2 is parented to 1. 595 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 596 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 597 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); 598 599 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); 600 EXPECT_EQ("[view=1,1 parent=null]", 601 ChangeViewDescription(connection2_->changes())); 602 603 // Embed() removed view 2. 604 { 605 std::vector<TestView> views; 606 connection_->GetViewTree(BuildViewId(1, 2), &views); 607 ASSERT_EQ(1u, views.size()); 608 EXPECT_EQ("view=1,2 parent=null", views[0].ToString()); 609 } 610 611 // |connection2_| should not see view 2. 612 { 613 std::vector<TestView> views; 614 connection2_->GetViewTree(BuildViewId(1, 1), &views); 615 ASSERT_EQ(1u, views.size()); 616 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); 617 } 618 { 619 std::vector<TestView> views; 620 connection2_->GetViewTree(BuildViewId(1, 2), &views); 621 EXPECT_TRUE(views.empty()); 622 } 623 624 // Views 3 and 4 in connection 2. 625 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); 626 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 4))); 627 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 3), BuildViewId(2, 4))); 628 629 // Connection 3 rooted at 2. 630 ASSERT_NO_FATAL_FAILURE( 631 EstablishThirdConnection(connection2_, BuildViewId(2, 3))); 632 633 // View 4 should no longer have a parent. 634 { 635 std::vector<TestView> views; 636 connection2_->GetViewTree(BuildViewId(2, 3), &views); 637 ASSERT_EQ(1u, views.size()); 638 EXPECT_EQ("view=2,3 parent=null", views[0].ToString()); 639 640 views.clear(); 641 connection2_->GetViewTree(BuildViewId(2, 4), &views); 642 ASSERT_EQ(1u, views.size()); 643 EXPECT_EQ("view=2,4 parent=null", views[0].ToString()); 644 } 645 646 // And view 4 should not be visible to connection 3. 647 { 648 std::vector<TestView> views; 649 connection3_->GetViewTree(BuildViewId(2, 3), &views); 650 ASSERT_EQ(1u, views.size()); 651 EXPECT_EQ("view=2,3 parent=null", views[0].ToString()); 652 } 653 } 654 655 // Verifies once Embed() has been invoked the parent connection can't see any 656 // children. 657 TEST_F(ViewManagerTest, CantAccessChildrenOfEmbeddedView) { 658 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 659 660 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 661 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 662 663 ASSERT_NO_FATAL_FAILURE( 664 EstablishThirdConnection(connection2_, BuildViewId(2, 2))); 665 666 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 3))); 667 ASSERT_TRUE(connection3_->AddView(BuildViewId(2, 2), BuildViewId(3, 3))); 668 669 // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a 670 // different connection. 671 { 672 std::vector<TestView> views; 673 connection2_->GetViewTree(BuildViewId(2, 2), &views); 674 ASSERT_EQ(1u, views.size()); 675 EXPECT_EQ("view=2,2 parent=1,1", views[0].ToString()); 676 } 677 678 { 679 std::vector<TestView> views; 680 connection2_->GetViewTree(BuildViewId(3, 3), &views); 681 EXPECT_TRUE(views.empty()); 682 } 683 684 // Connection 2 shouldn't be able to get view 3 at all. 685 { 686 std::vector<TestView> views; 687 connection2_->GetViewTree(BuildViewId(3, 3), &views); 688 EXPECT_TRUE(views.empty()); 689 } 690 691 // Connection 1 should be able to see it all (its the root). 692 { 693 std::vector<TestView> views; 694 connection_->GetViewTree(BuildViewId(1, 1), &views); 695 ASSERT_EQ(3u, views.size()); 696 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); 697 EXPECT_EQ("view=2,2 parent=1,1", views[1].ToString()); 698 EXPECT_EQ("view=3,3 parent=2,2", views[2].ToString()); 699 } 700 } 701 702 // Verifies once Embed() has been invoked the parent can't mutate the children. 703 TEST_F(ViewManagerTest, CantModifyChildrenOfEmbeddedView) { 704 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 705 706 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 707 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 708 709 ASSERT_NO_FATAL_FAILURE( 710 EstablishThirdConnection(connection2_, BuildViewId(2, 2))); 711 712 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); 713 // Connection 2 shouldn't be able to add anything to the view anymore. 714 ASSERT_FALSE(connection2_->AddView(BuildViewId(2, 2), BuildViewId(2, 3))); 715 716 // Create view 3 in connection 3 and add it to view 3. 717 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 3))); 718 ASSERT_TRUE(connection3_->AddView(BuildViewId(2, 2), BuildViewId(3, 3))); 719 720 // Connection 2 shouldn't be able to remove view 3. 721 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(3, 3))); 722 } 723 724 // Verifies client gets a valid id. 725 TEST_F(ViewManagerTest, CreateView) { 726 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 727 EXPECT_TRUE(connection_->changes().empty()); 728 729 // Can't create a view with the same id. 730 ASSERT_EQ(ERROR_CODE_VALUE_IN_USE, 731 connection_->CreateViewWithErrorCode(BuildViewId(1, 1))); 732 EXPECT_TRUE(connection_->changes().empty()); 733 734 // Can't create a view with a bogus connection id. 735 EXPECT_EQ(ERROR_CODE_ILLEGAL_ARGUMENT, 736 connection_->CreateViewWithErrorCode(BuildViewId(2, 1))); 737 EXPECT_TRUE(connection_->changes().empty()); 738 } 739 740 // Verifies AddView fails when view is already in position. 741 TEST_F(ViewManagerTest, AddViewWithNoChange) { 742 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 743 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3))); 744 745 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 746 747 // Make 3 a child of 2. 748 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3))); 749 750 // Try again, this should fail. 751 EXPECT_FALSE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3))); 752 } 753 754 // Verifies AddView fails when view is already in position. 755 TEST_F(ViewManagerTest, AddAncestorFails) { 756 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 757 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3))); 758 759 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 760 761 // Make 3 a child of 2. 762 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3))); 763 764 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3. 765 EXPECT_FALSE(connection_->AddView(BuildViewId(1, 3), BuildViewId(1, 2))); 766 } 767 768 // Verifies adding to root sends right notifications. 769 TEST_F(ViewManagerTest, AddToRoot) { 770 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 21))); 771 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3))); 772 773 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 774 775 // Make 3 a child of 21. 776 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 21), BuildViewId(1, 3))); 777 778 // Make 21 a child of 1. 779 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 21))); 780 781 // Connection 2 should not be told anything (because the view is from a 782 // different connection). Create a view to ensure we got a response from 783 // the server. 784 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 100))); 785 connection2_->CopyChangesFromTracker(); 786 EXPECT_TRUE(connection2_->changes().empty()); 787 } 788 789 // Verifies HierarchyChanged is correctly sent for various adds/removes. 790 TEST_F(ViewManagerTest, ViewHierarchyChangedViews) { 791 // 1,2->1,11. 792 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 793 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 11))); 794 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 11))); 795 796 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 797 798 // 1,1->1,2->1,11 799 { 800 // Client 2 should not get anything (1,2 is from another connection). 801 connection2_->ClearChanges(); 802 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); 803 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 100))); 804 connection2_->CopyChangesFromTracker(); 805 EXPECT_TRUE(connection2_->changes().empty()); 806 } 807 808 // 0,1->1,1->1,2->1,11. 809 { 810 // Client 2 is now connected to the root, so it should have gotten a drawn 811 // notification. 812 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 813 connection2_->DoRunLoopUntilChangesCount(1); 814 ASSERT_EQ(1u, connection2_->changes().size()); 815 EXPECT_EQ("DrawnStateChanged view=1,1 drawn=true", 816 ChangesToDescription1(connection2_->changes())[0]); 817 } 818 819 // 1,1->1,2->1,11. 820 { 821 // Client 2 is no longer connected to the root, should get drawn state 822 // changed. 823 ASSERT_TRUE(connection_->RemoveViewFromParent(BuildViewId(1, 1))); 824 connection2_->DoRunLoopUntilChangesCount(1); 825 ASSERT_EQ(1u, connection2_->changes().size()); 826 EXPECT_EQ("DrawnStateChanged view=1,1 drawn=false", 827 ChangesToDescription1(connection2_->changes())[0]); 828 } 829 830 // 1,1->1,2->1,11->1,111. 831 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 111))); 832 { 833 connection2_->ClearChanges(); 834 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 11), BuildViewId(1, 111))); 835 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 103))); 836 connection2_->CopyChangesFromTracker(); 837 EXPECT_TRUE(connection2_->changes().empty()); 838 } 839 840 // 0,1->1,1->1,2->1,11->1,111 841 { 842 connection2_->ClearChanges(); 843 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 844 connection2_->DoRunLoopUntilChangesCount(1); 845 ASSERT_EQ(1u, connection2_->changes().size()); 846 EXPECT_EQ("DrawnStateChanged view=1,1 drawn=true", 847 ChangesToDescription1(connection2_->changes())[0]); 848 } 849 } 850 851 TEST_F(ViewManagerTest, ViewHierarchyChangedAddingKnownToUnknown) { 852 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no 853 // parent). 854 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 855 856 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 11))); 857 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 858 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 21))); 859 860 // Set up the hierarchy. 861 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 862 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 11))); 863 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 2), BuildViewId(2, 21))); 864 865 // Remove 11, should result in a hierarchy change for the root. 866 { 867 connection_->ClearChanges(); 868 ASSERT_TRUE(connection2_->RemoveViewFromParent(BuildViewId(2, 11))); 869 870 connection_->DoRunLoopUntilChangesCount(1); 871 const Changes changes(ChangesToDescription1(connection_->changes())); 872 ASSERT_EQ(1u, changes.size()); 873 EXPECT_EQ("HierarchyChanged view=2,11 new_parent=null old_parent=1,1", 874 changes[0]); 875 } 876 877 // Add 2 to 1. 878 { 879 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 880 881 connection_->DoRunLoopUntilChangesCount(1); 882 const Changes changes(ChangesToDescription1(connection_->changes())); 883 ASSERT_EQ(1u, changes.size()); 884 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", 885 changes[0]); 886 EXPECT_EQ( 887 "[view=2,2 parent=1,1]," 888 "[view=2,21 parent=2,2]", 889 ChangeViewDescription(connection_->changes())); 890 } 891 } 892 893 TEST_F(ViewManagerTest, ReorderView) { 894 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 895 896 Id view1_id = BuildViewId(2, 1); 897 Id view2_id = BuildViewId(2, 2); 898 Id view3_id = BuildViewId(2, 3); 899 Id view4_id = BuildViewId(1, 4); // Peer to 1,1 900 Id view5_id = BuildViewId(1, 5); // Peer to 1,1 901 Id view6_id = BuildViewId(2, 6); // Child of 1,2. 902 Id view7_id = BuildViewId(2, 7); // Unparented. 903 Id view8_id = BuildViewId(2, 8); // Unparented. 904 ASSERT_TRUE(connection2_->CreateView(view1_id)); 905 ASSERT_TRUE(connection2_->CreateView(view2_id)); 906 ASSERT_TRUE(connection2_->CreateView(view3_id)); 907 ASSERT_TRUE(connection_->CreateView(view4_id)); 908 ASSERT_TRUE(connection_->CreateView(view5_id)); 909 ASSERT_TRUE(connection2_->CreateView(view6_id)); 910 ASSERT_TRUE(connection2_->CreateView(view7_id)); 911 ASSERT_TRUE(connection2_->CreateView(view8_id)); 912 ASSERT_TRUE(connection2_->AddView(view1_id, view2_id)); 913 ASSERT_TRUE(connection2_->AddView(view2_id, view6_id)); 914 ASSERT_TRUE(connection2_->AddView(view1_id, view3_id)); 915 ASSERT_TRUE( 916 connection_->AddView(ViewIdToTransportId(RootViewId()), view4_id)); 917 ASSERT_TRUE( 918 connection_->AddView(ViewIdToTransportId(RootViewId()), view5_id)); 919 920 ASSERT_TRUE( 921 connection_->AddView(ViewIdToTransportId(RootViewId()), view1_id)); 922 923 { 924 ASSERT_TRUE( 925 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_ABOVE)); 926 927 connection_->DoRunLoopUntilChangesCount(1); 928 const Changes changes(ChangesToDescription1(connection_->changes())); 929 ASSERT_EQ(1u, changes.size()); 930 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=above", changes[0]); 931 } 932 933 { 934 ASSERT_TRUE( 935 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_BELOW)); 936 937 connection_->DoRunLoopUntilChangesCount(1); 938 const Changes changes(ChangesToDescription1(connection_->changes())); 939 ASSERT_EQ(1u, changes.size()); 940 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=below", changes[0]); 941 } 942 943 // view2 is already below view3. 944 EXPECT_FALSE( 945 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_BELOW)); 946 947 // view4 & 5 are unknown to connection2_. 948 EXPECT_FALSE( 949 connection2_->ReorderView(view4_id, view5_id, ORDER_DIRECTION_ABOVE)); 950 951 // view6 & view3 have different parents. 952 EXPECT_FALSE( 953 connection_->ReorderView(view3_id, view6_id, ORDER_DIRECTION_ABOVE)); 954 955 // Non-existent view-ids 956 EXPECT_FALSE(connection_->ReorderView( 957 BuildViewId(1, 27), BuildViewId(1, 28), ORDER_DIRECTION_ABOVE)); 958 959 // view7 & view8 are un-parented. 960 EXPECT_FALSE( 961 connection_->ReorderView(view7_id, view8_id, ORDER_DIRECTION_ABOVE)); 962 } 963 964 // Verifies DeleteView works. 965 TEST_F(ViewManagerTest, DeleteView) { 966 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 967 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 968 969 // Make 2 a child of 1. 970 { 971 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 972 connection_->DoRunLoopUntilChangesCount(1); 973 const Changes changes(ChangesToDescription1(connection_->changes())); 974 ASSERT_EQ(1u, changes.size()); 975 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", 976 changes[0]); 977 } 978 979 // Delete 2. 980 { 981 ASSERT_TRUE(connection2_->DeleteView(BuildViewId(2, 2))); 982 EXPECT_TRUE(connection2_->changes().empty()); 983 984 connection_->DoRunLoopUntilChangesCount(1); 985 const Changes changes(ChangesToDescription1(connection_->changes())); 986 ASSERT_EQ(1u, changes.size()); 987 EXPECT_EQ("ViewDeleted view=2,2", changes[0]); 988 } 989 } 990 991 // Verifies DeleteView isn't allowed from a separate connection. 992 TEST_F(ViewManagerTest, DeleteViewFromAnotherConnectionDisallowed) { 993 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 994 EXPECT_FALSE(connection2_->DeleteView(BuildViewId(1, 1))); 995 } 996 997 // Verifies if a view was deleted and then reused that other clients are 998 // properly notified. 999 TEST_F(ViewManagerTest, ReuseDeletedViewId) { 1000 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 1001 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 1002 1003 // Add 2 to 1. 1004 { 1005 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 1006 1007 connection_->DoRunLoopUntilChangesCount(1); 1008 const Changes changes(ChangesToDescription1(connection_->changes())); 1009 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", 1010 changes[0]); 1011 EXPECT_EQ("[view=2,2 parent=1,1]", 1012 ChangeViewDescription(connection_->changes())); 1013 } 1014 1015 // Delete 2. 1016 { 1017 ASSERT_TRUE(connection2_->DeleteView(BuildViewId(2, 2))); 1018 1019 connection_->DoRunLoopUntilChangesCount(1); 1020 const Changes changes(ChangesToDescription1(connection_->changes())); 1021 ASSERT_EQ(1u, changes.size()); 1022 EXPECT_EQ("ViewDeleted view=2,2", changes[0]); 1023 } 1024 1025 // Create 2 again, and add it back to 1. Should get the same notification. 1026 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 1027 { 1028 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 1029 1030 connection_->DoRunLoopUntilChangesCount(1); 1031 const Changes changes(ChangesToDescription1(connection_->changes())); 1032 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", 1033 changes[0]); 1034 EXPECT_EQ("[view=2,2 parent=1,1]", 1035 ChangeViewDescription(connection_->changes())); 1036 } 1037 } 1038 1039 // Assertions for GetViewTree. 1040 TEST_F(ViewManagerTest, GetViewTree) { 1041 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 1042 1043 // Create 11 in first connection and make it a child of 1. 1044 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 11))); 1045 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1046 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 11))); 1047 1048 // Create two views in second connection, 2 and 3, both children of 1. 1049 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); 1050 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); 1051 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); 1052 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 3))); 1053 1054 // Verifies GetViewTree() on the root. The root connection sees all. 1055 { 1056 std::vector<TestView> views; 1057 connection_->GetViewTree(BuildViewId(0, 1), &views); 1058 ASSERT_EQ(5u, views.size()); 1059 EXPECT_EQ("view=0,1 parent=null", views[0].ToString()); 1060 EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString()); 1061 EXPECT_EQ("view=1,11 parent=1,1", views[2].ToString()); 1062 EXPECT_EQ("view=2,2 parent=1,1", views[3].ToString()); 1063 EXPECT_EQ("view=2,3 parent=1,1", views[4].ToString()); 1064 } 1065 1066 // Verifies GetViewTree() on the view 1,1. This does not include any children 1067 // as they are not from this connection. 1068 { 1069 std::vector<TestView> views; 1070 connection2_->GetViewTree(BuildViewId(1, 1), &views); 1071 ASSERT_EQ(1u, views.size()); 1072 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); 1073 } 1074 1075 // Connection 2 shouldn't be able to get the root tree. 1076 { 1077 std::vector<TestView> views; 1078 connection2_->GetViewTree(BuildViewId(0, 1), &views); 1079 ASSERT_EQ(0u, views.size()); 1080 } 1081 } 1082 1083 TEST_F(ViewManagerTest, SetViewBounds) { 1084 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1085 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1086 1087 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); 1088 1089 ASSERT_TRUE( 1090 connection_->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 100, 100))); 1091 1092 connection2_->DoRunLoopUntilChangesCount(1); 1093 const Changes changes(ChangesToDescription1(connection2_->changes())); 1094 ASSERT_EQ(1u, changes.size()); 1095 EXPECT_EQ("BoundsChanged view=1,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100", 1096 changes[0]); 1097 1098 // Should not be possible to change the bounds of a view created by another 1099 // connection. 1100 ASSERT_FALSE( 1101 connection2_->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 0, 0))); 1102 } 1103 1104 // Verify AddView fails when trying to manipulate views in other roots. 1105 TEST_F(ViewManagerTest, CantMoveViewsFromOtherRoot) { 1106 // Create 1 and 2 in the first connection. 1107 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1108 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 1109 1110 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); 1111 1112 // Try to move 2 to be a child of 1 from connection 2. This should fail as 2 1113 // should not be able to access 1. 1114 ASSERT_FALSE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); 1115 1116 // Try to reparent 1 to the root. A connection is not allowed to reparent its 1117 // roots. 1118 ASSERT_FALSE(connection2_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1119 } 1120 1121 // Verify RemoveViewFromParent fails for views that are descendants of the 1122 // roots. 1123 TEST_F(ViewManagerTest, CantRemoveViewsInOtherRoots) { 1124 // Create 1 and 2 in the first connection and parent both to the root. 1125 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1126 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 1127 1128 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1129 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 2))); 1130 1131 // Establish the second connection and give it the root 1. 1132 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); 1133 1134 // Connection 2 should not be able to remove view 2 or 1 from its parent. 1135 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(1, 2))); 1136 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(1, 1))); 1137 1138 // Create views 10 and 11 in 2. 1139 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 10))); 1140 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 11))); 1141 1142 // Parent 11 to 10. 1143 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 10), BuildViewId(2, 11))); 1144 // Remove 11 from 10. 1145 ASSERT_TRUE(connection2_->RemoveViewFromParent(BuildViewId(2, 11))); 1146 1147 // Verify nothing was actually removed. 1148 { 1149 std::vector<TestView> views; 1150 connection_->GetViewTree(BuildViewId(0, 1), &views); 1151 ASSERT_EQ(3u, views.size()); 1152 EXPECT_EQ("view=0,1 parent=null", views[0].ToString()); 1153 EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString()); 1154 EXPECT_EQ("view=1,2 parent=0,1", views[2].ToString()); 1155 } 1156 } 1157 1158 // Verify GetViewTree fails for views that are not descendants of the roots. 1159 TEST_F(ViewManagerTest, CantGetViewTreeOfOtherRoots) { 1160 // Create 1 and 2 in the first connection and parent both to the root. 1161 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1162 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 1163 1164 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1165 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 2))); 1166 1167 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); 1168 1169 std::vector<TestView> views; 1170 1171 // Should get nothing for the root. 1172 connection2_->GetViewTree(BuildViewId(0, 1), &views); 1173 ASSERT_TRUE(views.empty()); 1174 1175 // Should get nothing for view 2. 1176 connection2_->GetViewTree(BuildViewId(1, 2), &views); 1177 ASSERT_TRUE(views.empty()); 1178 1179 // Should get view 1 if asked for. 1180 connection2_->GetViewTree(BuildViewId(1, 1), &views); 1181 ASSERT_EQ(1u, views.size()); 1182 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); 1183 } 1184 1185 TEST_F(ViewManagerTest, OnViewInput) { 1186 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1187 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); 1188 1189 // Dispatch an event to the view and verify its received. 1190 { 1191 EventPtr event(Event::New()); 1192 event->action = static_cast<EventType>(1); 1193 connection_->view_manager()->DispatchOnViewInputEvent(BuildViewId(1, 1), 1194 event.Pass()); 1195 connection2_->DoRunLoopUntilChangesCount(1); 1196 const Changes changes(ChangesToDescription1(connection2_->changes())); 1197 ASSERT_EQ(1u, changes.size()); 1198 EXPECT_EQ("InputEvent view=1,1 event_action=1", changes[0]); 1199 } 1200 } 1201 1202 TEST_F(ViewManagerTest, EmbedWithSameViewId) { 1203 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 1204 1205 ASSERT_NO_FATAL_FAILURE( 1206 EstablishThirdConnection(connection_, BuildViewId(1, 1))); 1207 1208 // Connection2 should have been told the view was deleted. 1209 { 1210 connection2_->DoRunLoopUntilChangesCount(1); 1211 const Changes changes(ChangesToDescription1(connection2_->changes())); 1212 ASSERT_EQ(1u, changes.size()); 1213 EXPECT_EQ("ViewDeleted view=1,1", changes[0]); 1214 } 1215 1216 // Connection2 has no root. Verify it can't see view 1,1 anymore. 1217 { 1218 std::vector<TestView> views; 1219 connection2_->GetViewTree(BuildViewId(1, 1), &views); 1220 EXPECT_TRUE(views.empty()); 1221 } 1222 } 1223 1224 TEST_F(ViewManagerTest, EmbedWithSameViewId2) { 1225 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); 1226 1227 ASSERT_NO_FATAL_FAILURE( 1228 EstablishThirdConnection(connection_, BuildViewId(1, 1))); 1229 1230 // Connection2 should have been told the view was deleted. 1231 connection2_->DoRunLoopUntilChangesCount(1); 1232 connection2_->ClearChanges(); 1233 1234 // Create a view in the third connection and parent it to the root. 1235 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 1))); 1236 ASSERT_TRUE(connection3_->AddView(BuildViewId(1, 1), BuildViewId(3, 1))); 1237 1238 // Connection 1 should have been told about the add (it owns the view). 1239 { 1240 connection_->DoRunLoopUntilChangesCount(1); 1241 const Changes changes(ChangesToDescription1(connection_->changes())); 1242 ASSERT_EQ(1u, changes.size()); 1243 EXPECT_EQ("HierarchyChanged view=3,1 new_parent=1,1 old_parent=null", 1244 changes[0]); 1245 } 1246 1247 // Embed 1,1 again. 1248 { 1249 // We should get a new connection for the new embedding. 1250 ASSERT_TRUE(connection_->Embed(BuildViewId(1, 1), kTestServiceURL)); 1251 ViewManagerProxy* connection4 = ViewManagerProxy::WaitForInstance(); 1252 connection4->DoRunLoopUntilChangesCount(1); 1253 const std::vector<Change>& changes(connection4->changes()); 1254 ASSERT_EQ(1u, changes.size()); 1255 EXPECT_EQ("OnEmbed creator=mojo:test_url", 1256 ChangesToDescription1(changes)[0]); 1257 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes)); 1258 1259 // And 3 should get a delete. 1260 connection3_->DoRunLoopUntilChangesCount(1); 1261 ASSERT_EQ(1u, connection3_->changes().size()); 1262 EXPECT_EQ("ViewDeleted view=1,1", 1263 ChangesToDescription1(connection3_->changes())[0]); 1264 } 1265 1266 // Connection3_ has no root. Verify it can't see view 1,1 anymore. 1267 { 1268 std::vector<TestView> views; 1269 connection3_->GetViewTree(BuildViewId(1, 1), &views); 1270 EXPECT_TRUE(views.empty()); 1271 } 1272 1273 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as 1274 // connection3_ can no longer see 1,1. 1275 { 1276 std::vector<TestView> views; 1277 connection_->GetViewTree(BuildViewId(1, 1), &views); 1278 ASSERT_EQ(1u, views.size()); 1279 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); 1280 } 1281 1282 // Verify connection3_ can still see the view it created 3,1. 1283 { 1284 std::vector<TestView> views; 1285 connection3_->GetViewTree(BuildViewId(3, 1), &views); 1286 ASSERT_EQ(1u, views.size()); 1287 EXPECT_EQ("view=3,1 parent=null", views[0].ToString()); 1288 } 1289 } 1290 1291 // Assertions for SetViewVisibility. 1292 TEST_F(ViewManagerTest, SetViewVisibility) { 1293 // Create 1 and 2 in the first connection and parent both to the root. 1294 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1295 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 1296 1297 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1298 { 1299 std::vector<TestView> views; 1300 connection_->GetViewTree(BuildViewId(0, 1), &views); 1301 ASSERT_EQ(2u, views.size()); 1302 EXPECT_EQ("view=0,1 parent=null visible=true drawn=true", 1303 views[0].ToString2()); 1304 EXPECT_EQ("view=1,1 parent=0,1 visible=true drawn=true", 1305 views[1].ToString2()); 1306 } 1307 1308 // Hide 1. 1309 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), false)); 1310 { 1311 std::vector<TestView> views; 1312 connection_->GetViewTree(BuildViewId(1, 1), &views); 1313 ASSERT_EQ(1u, views.size()); 1314 EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false", 1315 views[0].ToString2()); 1316 } 1317 1318 // Attach 2 to 1. 1319 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); 1320 { 1321 std::vector<TestView> views; 1322 connection_->GetViewTree(BuildViewId(1, 1), &views); 1323 ASSERT_EQ(2u, views.size()); 1324 EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false", 1325 views[0].ToString2()); 1326 EXPECT_EQ("view=1,2 parent=1,1 visible=true drawn=false", 1327 views[1].ToString2()); 1328 } 1329 1330 // Show 1. 1331 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); 1332 { 1333 std::vector<TestView> views; 1334 connection_->GetViewTree(BuildViewId(1, 1), &views); 1335 ASSERT_EQ(2u, views.size()); 1336 EXPECT_EQ("view=1,1 parent=0,1 visible=true drawn=true", 1337 views[0].ToString2()); 1338 EXPECT_EQ("view=1,2 parent=1,1 visible=true drawn=true", 1339 views[1].ToString2()); 1340 } 1341 } 1342 1343 // Assertions for SetViewVisibility sending notifications. 1344 TEST_F(ViewManagerTest, SetViewVisibilityNotifications) { 1345 // Create 1,1 and 1,2, 1,2 and child of 1,1 and 1,1 a child of the root. 1346 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); 1347 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); 1348 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1349 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); 1350 1351 // Establish the second connection at 1,2. 1352 ASSERT_NO_FATAL_FAILURE( 1353 EstablishSecondConnectionWithRoot(BuildViewId(1, 2))); 1354 1355 // Add 2,3 as a child of 1,2. 1356 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); 1357 connection_->ClearChanges(); 1358 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 2), BuildViewId(2, 3))); 1359 connection_->DoRunLoopUntilChangesCount(1); 1360 1361 // Hide 1,2 from connection 1. Connection 2 should see this. 1362 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 2), false)); 1363 { 1364 connection2_->DoRunLoopUntilChangesCount(1); 1365 ASSERT_EQ(1u, connection2_->changes().size()); 1366 EXPECT_EQ("VisibilityChanged view=1,2 visible=false", 1367 ChangesToDescription1(connection2_->changes())[0]); 1368 } 1369 1370 // Show 1,2 from connection 2, connection 1 should be notified. 1371 ASSERT_TRUE(connection2_->SetViewVisibility(BuildViewId(1, 2), true)); 1372 { 1373 connection_->DoRunLoopUntilChangesCount(1); 1374 ASSERT_EQ(1u, connection_->changes().size()); 1375 EXPECT_EQ("VisibilityChanged view=1,2 visible=true", 1376 ChangesToDescription1(connection_->changes())[0]); 1377 } 1378 1379 // Hide 1,1, connection 2 should be told the draw state changed. 1380 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), false)); 1381 { 1382 connection2_->DoRunLoopUntilChangesCount(1); 1383 ASSERT_EQ(1u, connection2_->changes().size()); 1384 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=false", 1385 ChangesToDescription1(connection2_->changes())[0]); 1386 } 1387 1388 // Show 1,1 from connection 1. Connection 2 should see this. 1389 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); 1390 { 1391 connection2_->DoRunLoopUntilChangesCount(1); 1392 ASSERT_EQ(1u, connection2_->changes().size()); 1393 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=true", 1394 ChangesToDescription1(connection2_->changes())[0]); 1395 } 1396 1397 // Change visibility of 2,3, connection 1 should see this. 1398 connection_->ClearChanges(); 1399 ASSERT_TRUE(connection2_->SetViewVisibility(BuildViewId(2, 3), false)); 1400 { 1401 connection_->DoRunLoopUntilChangesCount(1); 1402 ASSERT_EQ(1u, connection_->changes().size()); 1403 EXPECT_EQ("VisibilityChanged view=2,3 visible=false", 1404 ChangesToDescription1(connection_->changes())[0]); 1405 } 1406 1407 // Remove 1,1 from the root, connection 2 should see drawn state changed. 1408 ASSERT_TRUE(connection_->RemoveViewFromParent(BuildViewId(1, 1))); 1409 { 1410 connection2_->DoRunLoopUntilChangesCount(1); 1411 ASSERT_EQ(1u, connection2_->changes().size()); 1412 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=false", 1413 ChangesToDescription1(connection2_->changes())[0]); 1414 } 1415 1416 // Add 1,1 back to the root, connection 2 should see drawn state changed. 1417 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); 1418 { 1419 connection2_->DoRunLoopUntilChangesCount(1); 1420 ASSERT_EQ(1u, connection2_->changes().size()); 1421 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=true", 1422 ChangesToDescription1(connection2_->changes())[0]); 1423 } 1424 } 1425 1426 // TODO(sky): add coverage of test that destroys connections and ensures other 1427 // connections get deletion notification. 1428 1429 // TODO(sky): need to better track changes to initial connection. For example, 1430 // that SetBounsdViews/AddView and the like don't result in messages to the 1431 // originating connection. 1432 1433 } // namespace service 1434 } // namespace mojo 1435