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.
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"
39 const char kTestServiceURL
[] = "mojo:test_url";
40 const char kTestServiceURL2
[] = "mojo:test_url2";
42 // ViewManagerProxy is a proxy to an ViewManagerService. It handles invoking
43 // ViewManagerService functions on the right thread in a synchronous manner
44 // (each ViewManagerService cover function blocks until the response from the
45 // ViewManagerService is returned). In addition it tracks the set of
46 // ViewManagerClient messages received by way of a vector of Changes. Use
47 // DoRunLoopUntilChangesCount() to wait for a certain number of messages to be
49 class ViewManagerProxy
: public TestChangeTracker::Delegate
{
51 explicit ViewManagerProxy(TestChangeTracker
* tracker
)
60 virtual ~ViewManagerProxy() {
63 // Runs a message loop until the single instance has been created.
64 static ViewManagerProxy
* WaitForInstance() {
67 ViewManagerProxy
* instance
= instance_
;
72 ViewManagerService
* view_manager() { return view_manager_
; }
74 // Runs the main loop until |count| changes have been received.
75 std::vector
<Change
> DoRunLoopUntilChangesCount(size_t count
) {
76 DCHECK_EQ(0u, quit_count_
);
77 if (tracker_
->changes()->size() >= count
) {
78 CopyChangesFromTracker();
81 quit_count_
= count
- tracker_
->changes()->size();
82 // Run the current message loop. When |count| Changes have been received,
88 const std::vector
<Change
>& changes() const { return changes_
; }
90 // Destroys the connection, blocking until done.
92 router_
->CloseMessagePipe();
97 tracker_
->changes()->clear();
100 void CopyChangesFromTracker() {
101 std::vector
<Change
> changes
;
102 tracker_
->changes()->swap(changes
);
103 changes_
.swap(changes
);
106 // The following functions are cover methods for ViewManagerService. They
107 // block until the result is received.
108 bool CreateView(Id view_id
) {
110 ErrorCode result
= ERROR_CODE_NONE
;
111 view_manager_
->CreateView(
113 base::Bind(&ViewManagerProxy::GotResultWithErrorCode
,
114 base::Unretained(this),
117 return result
== ERROR_CODE_NONE
;
119 ErrorCode
CreateViewWithErrorCode(Id view_id
) {
121 ErrorCode result
= ERROR_CODE_NONE
;
122 view_manager_
->CreateView(
124 base::Bind(&ViewManagerProxy::GotResultWithErrorCode
,
125 base::Unretained(this),
130 bool AddView(Id parent
, Id child
) {
133 view_manager_
->AddView(parent
, child
,
134 base::Bind(&ViewManagerProxy::GotResult
,
135 base::Unretained(this), &result
));
139 bool RemoveViewFromParent(Id view_id
) {
142 view_manager_
->RemoveViewFromParent(
145 &ViewManagerProxy::GotResult
, base::Unretained(this), &result
));
149 bool ReorderView(Id view_id
, Id relative_view_id
, OrderDirection direction
) {
152 view_manager_
->ReorderView(
157 &ViewManagerProxy::GotResult
, base::Unretained(this), &result
));
161 void GetViewTree(Id view_id
, std::vector
<TestView
>* views
) {
163 view_manager_
->GetViewTree(
166 &ViewManagerProxy::GotViewTree
, base::Unretained(this), views
));
169 bool Embed(const Id view_id
, const char* url
) {
171 base::AutoReset
<bool> auto_reset(&in_embed_
, true);
173 ServiceProviderPtr services
;
174 view_manager_
->Embed(
179 &ViewManagerProxy::GotResult
, base::Unretained(this), &result
));
183 bool DeleteView(Id view_id
) {
186 view_manager_
->DeleteView(
189 &ViewManagerProxy::GotResult
, base::Unretained(this), &result
));
193 bool SetViewBounds(Id view_id
, const gfx::Rect
& bounds
) {
196 view_manager_
->SetViewBounds(
200 &ViewManagerProxy::GotResult
, base::Unretained(this), &result
));
206 friend class TestViewManagerClientConnection
;
208 void set_router(mojo::internal::Router
* router
) { router_
= router
; }
210 void set_view_manager(ViewManagerService
* view_manager
) {
211 view_manager_
= view_manager
;
214 static void RunMainLoop() {
215 DCHECK(!main_run_loop_
);
216 main_run_loop_
= new base::RunLoop
;
217 main_run_loop_
->Run();
218 delete main_run_loop_
;
219 main_run_loop_
= NULL
;
222 void QuitCountReached() {
223 CopyChangesFromTracker();
224 main_run_loop_
->Quit();
227 static void SetInstance(ViewManagerProxy
* instance
) {
229 instance_
= instance
;
230 // Embed() runs its own run loop that is quit when the result is
231 // received. Embed() also results in a new instance. If we quit here while
232 // waiting for a Embed() we would prematurely return before we got the
233 // result from Embed().
234 if (!in_embed_
&& main_run_loop_
)
235 main_run_loop_
->Quit();
238 // Callbacks from the various ViewManagerService functions.
239 void GotResult(bool* result_cache
, bool result
) {
240 *result_cache
= result
;
241 DCHECK(main_run_loop_
);
242 main_run_loop_
->Quit();
245 void GotResultWithErrorCode(ErrorCode
* error_code_cache
,
246 ErrorCode error_code
) {
247 *error_code_cache
= error_code
;
248 DCHECK(main_run_loop_
);
249 main_run_loop_
->Quit();
252 void GotViewTree(std::vector
<TestView
>* views
, Array
<ViewDataPtr
> results
) {
253 ViewDatasToTestViews(results
, views
);
254 DCHECK(main_run_loop_
);
255 main_run_loop_
->Quit();
258 // TestChangeTracker::Delegate:
259 virtual void OnChangeAdded() OVERRIDE
{
260 if (quit_count_
> 0 && --quit_count_
== 0)
264 static ViewManagerProxy
* instance_
;
265 static base::RunLoop
* main_run_loop_
;
266 static bool in_embed_
;
268 TestChangeTracker
* tracker_
;
270 // MessageLoop of the test.
271 base::MessageLoop
* main_loop_
;
273 ViewManagerService
* view_manager_
;
275 // Number of changes we're waiting on until we quit the current loop.
278 std::vector
<Change
> changes_
;
280 mojo::internal::Router
* router_
;
282 DISALLOW_COPY_AND_ASSIGN(ViewManagerProxy
);
286 ViewManagerProxy
* ViewManagerProxy::instance_
= NULL
;
289 base::RunLoop
* ViewManagerProxy::main_run_loop_
= NULL
;
292 bool ViewManagerProxy::in_embed_
= false;
294 class TestViewManagerClientConnection
295 : public InterfaceImpl
<ViewManagerClient
> {
297 TestViewManagerClientConnection() : connection_(&tracker_
) {
298 tracker_
.set_delegate(&connection_
);
302 virtual void OnConnectionEstablished() OVERRIDE
{
303 connection_
.set_router(internal_state()->router());
304 connection_
.set_view_manager(client());
307 // ViewManagerClient:
308 virtual void OnEmbed(
309 ConnectionSpecificId connection_id
,
310 const String
& creator_url
,
312 InterfaceRequest
<ServiceProvider
> services
) OVERRIDE
{
313 tracker_
.OnEmbed(connection_id
, creator_url
, root
.Pass());
315 virtual void OnViewBoundsChanged(Id view_id
,
317 RectPtr new_bounds
) OVERRIDE
{
318 tracker_
.OnViewBoundsChanged(view_id
, old_bounds
.Pass(), new_bounds
.Pass());
320 virtual void OnViewHierarchyChanged(Id view
,
323 Array
<ViewDataPtr
> views
) OVERRIDE
{
324 tracker_
.OnViewHierarchyChanged(view
, new_parent
, old_parent
, views
.Pass());
326 virtual void OnViewReordered(Id view_id
,
328 OrderDirection direction
) OVERRIDE
{
329 tracker_
.OnViewReordered(view_id
, relative_view_id
, direction
);
331 virtual void OnViewDeleted(Id view
) OVERRIDE
{ tracker_
.OnViewDeleted(view
); }
332 virtual void OnViewInputEvent(Id view_id
,
334 const Callback
<void()>& callback
) OVERRIDE
{
335 tracker_
.OnViewInputEvent(view_id
, event
.Pass());
339 InterfaceRequest
<ServiceProvider
> service_provider
) OVERRIDE
{
340 tracker_
.DelegateEmbed(url
);
342 virtual void DispatchOnViewInputEvent(mojo::EventPtr event
) OVERRIDE
{
346 TestChangeTracker tracker_
;
347 ViewManagerProxy connection_
;
349 DISALLOW_COPY_AND_ASSIGN(TestViewManagerClientConnection
);
352 // Used with ViewManagerService::Embed(). Creates a
353 // TestViewManagerClientConnection, which creates and owns the ViewManagerProxy.
354 class EmbedApplicationLoader
: public ApplicationLoader
,
356 public InterfaceFactory
<ViewManagerClient
> {
358 EmbedApplicationLoader() {}
359 virtual ~EmbedApplicationLoader() {}
361 // ApplicationLoader implementation:
362 virtual void Load(ApplicationManager
* manager
,
364 scoped_refptr
<LoadCallbacks
> callbacks
) OVERRIDE
{
365 ScopedMessagePipeHandle shell_handle
= callbacks
->RegisterApplication();
366 if (!shell_handle
.is_valid())
368 scoped_ptr
<ApplicationImpl
> app(new ApplicationImpl(this,
369 shell_handle
.Pass()));
370 apps_
.push_back(app
.release());
372 virtual void OnApplicationError(ApplicationManager
* manager
,
373 const GURL
& url
) OVERRIDE
{}
375 // ApplicationDelegate implementation:
376 virtual bool ConfigureIncomingConnection(ApplicationConnection
* connection
)
378 connection
->AddService(this);
382 // InterfaceFactory<ViewManagerClient> implementation:
383 virtual void Create(ApplicationConnection
* connection
,
384 InterfaceRequest
<ViewManagerClient
> request
) OVERRIDE
{
385 BindToRequest(new TestViewManagerClientConnection
, &request
);
389 ScopedVector
<ApplicationImpl
> apps_
;
391 DISALLOW_COPY_AND_ASSIGN(EmbedApplicationLoader
);
394 // Creates an id used for transport from the specified parameters.
395 Id
BuildViewId(ConnectionSpecificId connection_id
,
396 ConnectionSpecificId view_id
) {
397 return (connection_id
<< 16) | view_id
;
400 // Callback from Embed(). |result| is the result of the
401 // Embed() call and |run_loop| the nested RunLoop.
402 void EmbedCallback(bool* result_cache
, base::RunLoop
* run_loop
, bool result
) {
403 *result_cache
= result
;
407 // Embed from an application that does not yet have a view manager connection.
408 // Blocks until result is determined.
409 bool InitEmbed(ViewManagerInitService
* view_manager_init
,
410 const std::string
& url
,
411 size_t number_of_calls
) {
413 base::RunLoop run_loop
;
414 for (size_t i
= 0; i
< number_of_calls
; ++i
) {
415 ServiceProviderPtr sp
;
416 view_manager_init
->Embed(url
, sp
.Pass(),
417 base::Bind(&EmbedCallback
, &result
, &run_loop
));
425 typedef std::vector
<std::string
> Changes
;
427 class ViewManagerTest
: public testing::Test
{
432 connection3_(NULL
) {}
434 virtual void SetUp() OVERRIDE
{
437 test_helper_
.SetLoaderForURL(
438 scoped_ptr
<ApplicationLoader
>(new EmbedApplicationLoader()),
439 GURL(kTestServiceURL
));
441 test_helper_
.SetLoaderForURL(
442 scoped_ptr
<ApplicationLoader
>(new EmbedApplicationLoader()),
443 GURL(kTestServiceURL2
));
445 test_helper_
.application_manager()->ConnectToService(
446 GURL("mojo:mojo_view_manager"), &view_manager_init_
);
447 ASSERT_TRUE(InitEmbed(view_manager_init_
.get(), kTestServiceURL
, 1));
449 connection_
= ViewManagerProxy::WaitForInstance();
450 ASSERT_TRUE(connection_
!= NULL
);
451 connection_
->DoRunLoopUntilChangesCount(1);
454 virtual void TearDown() OVERRIDE
{
456 connection3_
->Destroy();
458 connection2_
->Destroy();
460 connection_
->Destroy();
464 void EstablishSecondConnectionWithRoot(Id root_id
) {
465 ASSERT_TRUE(connection_
->Embed(root_id
, kTestServiceURL
));
466 connection2_
= ViewManagerProxy::WaitForInstance();
467 ASSERT_TRUE(connection2_
!= NULL
);
468 connection2_
->DoRunLoopUntilChangesCount(1);
469 ASSERT_EQ(1u, connection2_
->changes().size());
472 // Creates a second connection to the viewmanager.
473 void EstablishSecondConnection(bool create_initial_view
) {
474 if (create_initial_view
)
475 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
476 ASSERT_NO_FATAL_FAILURE(
477 EstablishSecondConnectionWithRoot(BuildViewId(1, 1)));
478 const std::vector
<Change
>& changes(connection2_
->changes());
479 ASSERT_EQ(1u, changes
.size());
480 EXPECT_EQ("OnEmbed creator=mojo:test_url",
481 ChangesToDescription1(changes
)[0]);
482 if (create_initial_view
) {
483 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes
));
487 void EstablishThirdConnection(ViewManagerProxy
* owner
, Id root_id
) {
488 ASSERT_TRUE(connection3_
== NULL
);
489 ASSERT_TRUE(owner
->Embed(root_id
, kTestServiceURL2
));
490 connection3_
= ViewManagerProxy::WaitForInstance();
491 ASSERT_TRUE(connection3_
!= NULL
);
492 connection3_
->DoRunLoopUntilChangesCount(1);
493 ASSERT_EQ(1u, connection3_
->changes().size());
494 EXPECT_EQ("OnEmbed creator=mojo:test_url",
495 ChangesToDescription1(connection3_
->changes())[0]);
498 void DestroySecondConnection() {
499 connection2_
->Destroy();
503 base::ShadowingAtExitManager at_exit_
;
504 shell::ShellTestHelper test_helper_
;
506 ViewManagerInitServicePtr view_manager_init_
;
508 // NOTE: this connection is the root. As such, it has special permissions.
509 ViewManagerProxy
* connection_
;
510 ViewManagerProxy
* connection2_
;
511 ViewManagerProxy
* connection3_
;
513 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest
);
516 TEST_F(ViewManagerTest
, SecondEmbedRoot_InitService
) {
517 ASSERT_TRUE(InitEmbed(view_manager_init_
.get(), kTestServiceURL
, 1));
518 connection_
->DoRunLoopUntilChangesCount(1);
519 EXPECT_EQ(kTestServiceURL
, connection_
->changes()[0].embed_url
);
522 TEST_F(ViewManagerTest
, SecondEmbedRoot_Service
) {
523 ASSERT_TRUE(connection_
->Embed(BuildViewId(0, 0), kTestServiceURL
));
524 connection_
->DoRunLoopUntilChangesCount(1);
525 EXPECT_EQ(kTestServiceURL
, connection_
->changes()[0].embed_url
);
528 TEST_F(ViewManagerTest
, MultipleEmbedRootsBeforeWTHReady
) {
529 ASSERT_TRUE(InitEmbed(view_manager_init_
.get(), kTestServiceURL
, 2));
530 connection_
->DoRunLoopUntilChangesCount(2);
531 EXPECT_EQ(kTestServiceURL
, connection_
->changes()[0].embed_url
);
532 EXPECT_EQ(kTestServiceURL
, connection_
->changes()[1].embed_url
);
535 // Verifies client gets a valid id.
536 #if defined(OS_LINUX)
537 // http://crbug.com/396492
538 #define MAYBE_ValidId DISABLED_ValidId
540 #define MAYBE_ValidId ValidId
542 TEST_F(ViewManagerTest
, MAYBE_ValidId
) {
543 // TODO(beng): this should really have the URL of the application that
544 // connected to ViewManagerInit.
545 EXPECT_EQ("OnEmbed creator=",
546 ChangesToDescription1(connection_
->changes())[0]);
548 // All these tests assume 1 for the client id. The only real assertion here is
549 // the client id is not zero, but adding this as rest of code here assumes 1.
550 EXPECT_EQ(1, connection_
->changes()[0].connection_id
);
553 // Verifies two clients/connections get different ids.
554 TEST_F(ViewManagerTest
, TwoClientsGetDifferentConnectionIds
) {
555 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
556 EXPECT_EQ("OnEmbed creator=mojo:test_url",
557 ChangesToDescription1(connection2_
->changes())[0]);
559 // It isn't strictly necessary that the second connection gets 2, but these
560 // tests are written assuming that is the case. The key thing is the
561 // connection ids of |connection_| and |connection2_| differ.
562 EXPECT_EQ(2, connection2_
->changes()[0].connection_id
);
565 // Verifies when Embed() is invoked any child views are removed.
566 TEST_F(ViewManagerTest
, ViewsRemovedWhenEmbedding
) {
567 // Two views 1 and 2. 2 is parented to 1.
568 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
569 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
570 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 1), BuildViewId(1, 2)));
572 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
573 EXPECT_EQ("[view=1,1 parent=null]",
574 ChangeViewDescription(connection2_
->changes()));
576 // Embed() removed view 2.
578 std::vector
<TestView
> views
;
579 connection_
->GetViewTree(BuildViewId(1, 2), &views
);
580 ASSERT_EQ(1u, views
.size());
581 EXPECT_EQ("view=1,2 parent=null", views
[0].ToString());
584 // |connection2_| should not see view 2.
586 std::vector
<TestView
> views
;
587 connection2_
->GetViewTree(BuildViewId(1, 1), &views
);
588 ASSERT_EQ(1u, views
.size());
589 EXPECT_EQ("view=1,1 parent=null", views
[0].ToString());
592 std::vector
<TestView
> views
;
593 connection2_
->GetViewTree(BuildViewId(1, 2), &views
);
594 EXPECT_TRUE(views
.empty());
597 // Views 3 and 4 in connection 2.
598 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 3)));
599 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 4)));
600 ASSERT_TRUE(connection2_
->AddView(BuildViewId(2, 3), BuildViewId(2, 4)));
602 // Connection 3 rooted at 2.
603 ASSERT_NO_FATAL_FAILURE(
604 EstablishThirdConnection(connection2_
, BuildViewId(2, 3)));
606 // View 4 should no longer have a parent.
608 std::vector
<TestView
> views
;
609 connection2_
->GetViewTree(BuildViewId(2, 3), &views
);
610 ASSERT_EQ(1u, views
.size());
611 EXPECT_EQ("view=2,3 parent=null", views
[0].ToString());
614 connection2_
->GetViewTree(BuildViewId(2, 4), &views
);
615 ASSERT_EQ(1u, views
.size());
616 EXPECT_EQ("view=2,4 parent=null", views
[0].ToString());
619 // And view 4 should not be visible to connection 3.
621 std::vector
<TestView
> views
;
622 connection3_
->GetViewTree(BuildViewId(2, 3), &views
);
623 ASSERT_EQ(1u, views
.size());
624 EXPECT_EQ("view=2,3 parent=null", views
[0].ToString());
628 // Verifies once Embed() has been invoked the parent connection can't see any
630 TEST_F(ViewManagerTest
, CantAccessChildrenOfEmbeddedView
) {
631 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
633 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
634 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
636 ASSERT_NO_FATAL_FAILURE(
637 EstablishThirdConnection(connection2_
, BuildViewId(2, 2)));
639 ASSERT_TRUE(connection3_
->CreateView(BuildViewId(3, 3)));
640 ASSERT_TRUE(connection3_
->AddView(BuildViewId(2, 2), BuildViewId(3, 3)));
642 // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a
643 // different connection.
645 std::vector
<TestView
> views
;
646 connection2_
->GetViewTree(BuildViewId(2, 2), &views
);
647 ASSERT_EQ(1u, views
.size());
648 EXPECT_EQ("view=2,2 parent=1,1", views
[0].ToString());
652 std::vector
<TestView
> views
;
653 connection2_
->GetViewTree(BuildViewId(3, 3), &views
);
654 EXPECT_TRUE(views
.empty());
657 // Connection 2 shouldn't be able to get view 3 at all.
659 std::vector
<TestView
> views
;
660 connection2_
->GetViewTree(BuildViewId(3, 3), &views
);
661 EXPECT_TRUE(views
.empty());
664 // Connection 1 should be able to see it all (its the root).
666 std::vector
<TestView
> views
;
667 connection_
->GetViewTree(BuildViewId(1, 1), &views
);
668 ASSERT_EQ(3u, views
.size());
669 EXPECT_EQ("view=1,1 parent=null", views
[0].ToString());
670 EXPECT_EQ("view=2,2 parent=1,1", views
[1].ToString());
671 EXPECT_EQ("view=3,3 parent=2,2", views
[2].ToString());
675 // Verifies once Embed() has been invoked the parent can't mutate the children.
676 TEST_F(ViewManagerTest
, CantModifyChildrenOfEmbeddedView
) {
677 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
679 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
680 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
682 ASSERT_NO_FATAL_FAILURE(
683 EstablishThirdConnection(connection2_
, BuildViewId(2, 2)));
685 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 3)));
686 // Connection 2 shouldn't be able to add anything to the view anymore.
687 ASSERT_FALSE(connection2_
->AddView(BuildViewId(2, 2), BuildViewId(2, 3)));
689 // Create view 3 in connection 3 and add it to view 3.
690 ASSERT_TRUE(connection3_
->CreateView(BuildViewId(3, 3)));
691 ASSERT_TRUE(connection3_
->AddView(BuildViewId(2, 2), BuildViewId(3, 3)));
693 // Connection 2 shouldn't be able to remove view 3.
694 ASSERT_FALSE(connection2_
->RemoveViewFromParent(BuildViewId(3, 3)));
697 // Verifies client gets a valid id.
698 TEST_F(ViewManagerTest
, CreateView
) {
699 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
700 EXPECT_TRUE(connection_
->changes().empty());
702 // Can't create a view with the same id.
703 ASSERT_EQ(ERROR_CODE_VALUE_IN_USE
,
704 connection_
->CreateViewWithErrorCode(BuildViewId(1, 1)));
705 EXPECT_TRUE(connection_
->changes().empty());
707 // Can't create a view with a bogus connection id.
708 EXPECT_EQ(ERROR_CODE_ILLEGAL_ARGUMENT
,
709 connection_
->CreateViewWithErrorCode(BuildViewId(2, 1)));
710 EXPECT_TRUE(connection_
->changes().empty());
713 // Verifies AddView fails when view is already in position.
714 TEST_F(ViewManagerTest
, AddViewWithNoChange
) {
715 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
716 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 3)));
718 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
720 // Make 3 a child of 2.
721 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 2), BuildViewId(1, 3)));
723 // Try again, this should fail.
724 EXPECT_FALSE(connection_
->AddView(BuildViewId(1, 2), BuildViewId(1, 3)));
727 // Verifies AddView fails when view is already in position.
728 TEST_F(ViewManagerTest
, AddAncestorFails
) {
729 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
730 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 3)));
732 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
734 // Make 3 a child of 2.
735 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 2), BuildViewId(1, 3)));
737 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
738 EXPECT_FALSE(connection_
->AddView(BuildViewId(1, 3), BuildViewId(1, 2)));
741 // Verifies adding to root sends right notifications.
742 TEST_F(ViewManagerTest
, AddToRoot
) {
743 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 21)));
744 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 3)));
746 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
748 // Make 3 a child of 21.
749 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 21), BuildViewId(1, 3)));
751 // Make 21 a child of 1.
752 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 1), BuildViewId(1, 21)));
754 // Connection 2 should not be told anything (because the view is from a
755 // different connection). Create a view to ensure we got a response from
757 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 100)));
758 connection2_
->CopyChangesFromTracker();
759 EXPECT_TRUE(connection2_
->changes().empty());
762 // Verifies HierarchyChanged is correctly sent for various adds/removes.
763 TEST_F(ViewManagerTest
, ViewHierarchyChangedViews
) {
765 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
766 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 11)));
767 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 2), BuildViewId(1, 11)));
769 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
773 // Client 2 should not get anything (1,2 is from another connection).
774 connection2_
->ClearChanges();
775 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 1), BuildViewId(1, 2)));
776 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 100)));
777 connection2_
->CopyChangesFromTracker();
778 EXPECT_TRUE(connection2_
->changes().empty());
781 // 0,1->1,1->1,2->1,11.
783 // Again, client 2 should not get anything.
784 connection2_
->ClearChanges();
785 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
786 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 101)));
787 connection2_
->CopyChangesFromTracker();
788 EXPECT_TRUE(connection2_
->changes().empty());
793 connection2_
->ClearChanges();
794 ASSERT_TRUE(connection_
->RemoveViewFromParent(BuildViewId(1, 1)));
795 EXPECT_TRUE(connection_
->changes().empty());
796 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 102)));
797 connection2_
->CopyChangesFromTracker();
798 EXPECT_TRUE(connection2_
->changes().empty());
801 // 1,1->1,2->1,11->1,111.
802 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 111)));
804 connection2_
->ClearChanges();
805 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 11), BuildViewId(1, 111)));
806 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 103)));
807 connection2_
->CopyChangesFromTracker();
808 EXPECT_TRUE(connection2_
->changes().empty());
811 // 0,1->1,1->1,2->1,11->1,111
813 connection2_
->ClearChanges();
814 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
815 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 104)));
816 connection2_
->CopyChangesFromTracker();
817 EXPECT_TRUE(connection2_
->changes().empty());
821 TEST_F(ViewManagerTest
, ViewHierarchyChangedAddingKnownToUnknown
) {
822 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no
824 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
826 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 11)));
827 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
828 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 21)));
830 // Set up the hierarchy.
831 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
832 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 11)));
833 ASSERT_TRUE(connection2_
->AddView(BuildViewId(2, 2), BuildViewId(2, 21)));
835 // Remove 11, should result in a hierarchy change for the root.
837 connection_
->ClearChanges();
838 ASSERT_TRUE(connection2_
->RemoveViewFromParent(BuildViewId(2, 11)));
840 connection_
->DoRunLoopUntilChangesCount(1);
841 const Changes
changes(ChangesToDescription1(connection_
->changes()));
842 ASSERT_EQ(1u, changes
.size());
843 EXPECT_EQ("HierarchyChanged view=2,11 new_parent=null old_parent=1,1",
849 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
851 connection_
->DoRunLoopUntilChangesCount(1);
852 const Changes
changes(ChangesToDescription1(connection_
->changes()));
853 ASSERT_EQ(1u, changes
.size());
854 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
857 "[view=2,2 parent=1,1],"
858 "[view=2,21 parent=2,2]",
859 ChangeViewDescription(connection_
->changes()));
863 TEST_F(ViewManagerTest
, ReorderView
) {
864 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
866 Id view1_id
= BuildViewId(2, 1);
867 Id view2_id
= BuildViewId(2, 2);
868 Id view3_id
= BuildViewId(2, 3);
869 Id view4_id
= BuildViewId(1, 4); // Peer to 1,1
870 Id view5_id
= BuildViewId(1, 5); // Peer to 1,1
871 Id view6_id
= BuildViewId(2, 6); // Child of 1,2.
872 Id view7_id
= BuildViewId(2, 7); // Unparented.
873 Id view8_id
= BuildViewId(2, 8); // Unparented.
874 ASSERT_TRUE(connection2_
->CreateView(view1_id
));
875 ASSERT_TRUE(connection2_
->CreateView(view2_id
));
876 ASSERT_TRUE(connection2_
->CreateView(view3_id
));
877 ASSERT_TRUE(connection_
->CreateView(view4_id
));
878 ASSERT_TRUE(connection_
->CreateView(view5_id
));
879 ASSERT_TRUE(connection2_
->CreateView(view6_id
));
880 ASSERT_TRUE(connection2_
->CreateView(view7_id
));
881 ASSERT_TRUE(connection2_
->CreateView(view8_id
));
882 ASSERT_TRUE(connection2_
->AddView(view1_id
, view2_id
));
883 ASSERT_TRUE(connection2_
->AddView(view2_id
, view6_id
));
884 ASSERT_TRUE(connection2_
->AddView(view1_id
, view3_id
));
886 connection_
->AddView(ViewIdToTransportId(RootViewId()), view4_id
));
888 connection_
->AddView(ViewIdToTransportId(RootViewId()), view5_id
));
891 connection_
->AddView(ViewIdToTransportId(RootViewId()), view1_id
));
895 connection2_
->ReorderView(view2_id
, view3_id
, ORDER_DIRECTION_ABOVE
));
897 connection_
->DoRunLoopUntilChangesCount(1);
898 const Changes
changes(ChangesToDescription1(connection_
->changes()));
899 ASSERT_EQ(1u, changes
.size());
900 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=above", changes
[0]);
905 connection2_
->ReorderView(view2_id
, view3_id
, ORDER_DIRECTION_BELOW
));
907 connection_
->DoRunLoopUntilChangesCount(1);
908 const Changes
changes(ChangesToDescription1(connection_
->changes()));
909 ASSERT_EQ(1u, changes
.size());
910 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=below", changes
[0]);
913 // view2 is already below view3.
915 connection2_
->ReorderView(view2_id
, view3_id
, ORDER_DIRECTION_BELOW
));
917 // view4 & 5 are unknown to connection2_.
919 connection2_
->ReorderView(view4_id
, view5_id
, ORDER_DIRECTION_ABOVE
));
921 // view6 & view3 have different parents.
923 connection_
->ReorderView(view3_id
, view6_id
, ORDER_DIRECTION_ABOVE
));
925 // Non-existent view-ids
926 EXPECT_FALSE(connection_
->ReorderView(
927 BuildViewId(1, 27), BuildViewId(1, 28), ORDER_DIRECTION_ABOVE
));
929 // view7 & view8 are un-parented.
931 connection_
->ReorderView(view7_id
, view8_id
, ORDER_DIRECTION_ABOVE
));
934 // Verifies DeleteView works.
935 TEST_F(ViewManagerTest
, DeleteView
) {
936 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
937 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
939 // Make 2 a child of 1.
941 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
942 connection_
->DoRunLoopUntilChangesCount(1);
943 const Changes
changes(ChangesToDescription1(connection_
->changes()));
944 ASSERT_EQ(1u, changes
.size());
945 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
951 ASSERT_TRUE(connection2_
->DeleteView(BuildViewId(2, 2)));
952 EXPECT_TRUE(connection2_
->changes().empty());
954 connection_
->DoRunLoopUntilChangesCount(1);
955 const Changes
changes(ChangesToDescription1(connection_
->changes()));
956 ASSERT_EQ(1u, changes
.size());
957 EXPECT_EQ("ViewDeleted view=2,2", changes
[0]);
961 // Verifies DeleteView isn't allowed from a separate connection.
962 TEST_F(ViewManagerTest
, DeleteViewFromAnotherConnectionDisallowed
) {
963 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
964 EXPECT_FALSE(connection2_
->DeleteView(BuildViewId(1, 1)));
967 // Verifies if a view was deleted and then reused that other clients are
968 // properly notified.
969 TEST_F(ViewManagerTest
, ReuseDeletedViewId
) {
970 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
971 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
975 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
977 connection_
->DoRunLoopUntilChangesCount(1);
978 const Changes
changes(ChangesToDescription1(connection_
->changes()));
979 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
981 EXPECT_EQ("[view=2,2 parent=1,1]",
982 ChangeViewDescription(connection_
->changes()));
987 ASSERT_TRUE(connection2_
->DeleteView(BuildViewId(2, 2)));
989 connection_
->DoRunLoopUntilChangesCount(1);
990 const Changes
changes(ChangesToDescription1(connection_
->changes()));
991 ASSERT_EQ(1u, changes
.size());
992 EXPECT_EQ("ViewDeleted view=2,2", changes
[0]);
995 // Create 2 again, and add it back to 1. Should get the same notification.
996 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
998 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
1000 connection_
->DoRunLoopUntilChangesCount(1);
1001 const Changes
changes(ChangesToDescription1(connection_
->changes()));
1002 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
1004 EXPECT_EQ("[view=2,2 parent=1,1]",
1005 ChangeViewDescription(connection_
->changes()));
1009 // Assertions for GetViewTree.
1010 TEST_F(ViewManagerTest
, GetViewTree
) {
1011 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1013 // Create 11 in first connection and make it a child of 1.
1014 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 11)));
1015 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1016 ASSERT_TRUE(connection_
->AddView(BuildViewId(1, 1), BuildViewId(1, 11)));
1018 // Create two views in second connection, 2 and 3, both children of 1.
1019 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 2)));
1020 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 3)));
1021 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
1022 ASSERT_TRUE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(2, 3)));
1024 // Verifies GetViewTree() on the root. The root connection sees all.
1026 std::vector
<TestView
> views
;
1027 connection_
->GetViewTree(BuildViewId(0, 1), &views
);
1028 ASSERT_EQ(5u, views
.size());
1029 EXPECT_EQ("view=0,1 parent=null", views
[0].ToString());
1030 EXPECT_EQ("view=1,1 parent=0,1", views
[1].ToString());
1031 EXPECT_EQ("view=1,11 parent=1,1", views
[2].ToString());
1032 EXPECT_EQ("view=2,2 parent=1,1", views
[3].ToString());
1033 EXPECT_EQ("view=2,3 parent=1,1", views
[4].ToString());
1036 // Verifies GetViewTree() on the view 1,1. This does not include any children
1037 // as they are not from this connection.
1039 std::vector
<TestView
> views
;
1040 connection2_
->GetViewTree(BuildViewId(1, 1), &views
);
1041 ASSERT_EQ(1u, views
.size());
1042 EXPECT_EQ("view=1,1 parent=null", views
[0].ToString());
1045 // Connection 2 shouldn't be able to get the root tree.
1047 std::vector
<TestView
> views
;
1048 connection2_
->GetViewTree(BuildViewId(0, 1), &views
);
1049 ASSERT_EQ(0u, views
.size());
1053 TEST_F(ViewManagerTest
, SetViewBounds
) {
1054 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
1055 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1057 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1060 connection_
->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 100, 100)));
1062 connection2_
->DoRunLoopUntilChangesCount(1);
1063 const Changes
changes(ChangesToDescription1(connection2_
->changes()));
1064 ASSERT_EQ(1u, changes
.size());
1065 EXPECT_EQ("BoundsChanged view=1,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100",
1068 // Should not be possible to change the bounds of a view created by another
1071 connection2_
->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 0, 0)));
1074 // Verify AddView fails when trying to manipulate views in other roots.
1075 TEST_F(ViewManagerTest
, CantMoveViewsFromOtherRoot
) {
1076 // Create 1 and 2 in the first connection.
1077 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
1078 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
1080 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1082 // Try to move 2 to be a child of 1 from connection 2. This should fail as 2
1083 // should not be able to access 1.
1084 ASSERT_FALSE(connection2_
->AddView(BuildViewId(1, 1), BuildViewId(1, 2)));
1086 // Try to reparent 1 to the root. A connection is not allowed to reparent its
1088 ASSERT_FALSE(connection2_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1091 // Verify RemoveViewFromParent fails for views that are descendants of the
1093 TEST_F(ViewManagerTest
, CantRemoveViewsInOtherRoots
) {
1094 // Create 1 and 2 in the first connection and parent both to the root.
1095 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
1096 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
1098 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1099 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 2)));
1101 // Establish the second connection and give it the root 1.
1102 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1104 // Connection 2 should not be able to remove view 2 or 1 from its parent.
1105 ASSERT_FALSE(connection2_
->RemoveViewFromParent(BuildViewId(1, 2)));
1106 ASSERT_FALSE(connection2_
->RemoveViewFromParent(BuildViewId(1, 1)));
1108 // Create views 10 and 11 in 2.
1109 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 10)));
1110 ASSERT_TRUE(connection2_
->CreateView(BuildViewId(2, 11)));
1113 ASSERT_TRUE(connection2_
->AddView(BuildViewId(2, 10), BuildViewId(2, 11)));
1114 // Remove 11 from 10.
1115 ASSERT_TRUE(connection2_
->RemoveViewFromParent(BuildViewId(2, 11)));
1117 // Verify nothing was actually removed.
1119 std::vector
<TestView
> views
;
1120 connection_
->GetViewTree(BuildViewId(0, 1), &views
);
1121 ASSERT_EQ(3u, views
.size());
1122 EXPECT_EQ("view=0,1 parent=null", views
[0].ToString());
1123 EXPECT_EQ("view=1,1 parent=0,1", views
[1].ToString());
1124 EXPECT_EQ("view=1,2 parent=0,1", views
[2].ToString());
1128 // Verify GetViewTree fails for views that are not descendants of the roots.
1129 TEST_F(ViewManagerTest
, CantGetViewTreeOfOtherRoots
) {
1130 // Create 1 and 2 in the first connection and parent both to the root.
1131 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
1132 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
1134 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1135 ASSERT_TRUE(connection_
->AddView(BuildViewId(0, 1), BuildViewId(1, 2)));
1137 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1139 std::vector
<TestView
> views
;
1141 // Should get nothing for the root.
1142 connection2_
->GetViewTree(BuildViewId(0, 1), &views
);
1143 ASSERT_TRUE(views
.empty());
1145 // Should get nothing for view 2.
1146 connection2_
->GetViewTree(BuildViewId(1, 2), &views
);
1147 ASSERT_TRUE(views
.empty());
1149 // Should get view 1 if asked for.
1150 connection2_
->GetViewTree(BuildViewId(1, 1), &views
);
1151 ASSERT_EQ(1u, views
.size());
1152 EXPECT_EQ("view=1,1 parent=null", views
[0].ToString());
1155 TEST_F(ViewManagerTest
, ConnectTwice
) {
1156 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
1157 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 2)));
1159 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1161 // Try to connect again to 1,1, this should fail as already connected to that
1163 ASSERT_FALSE(connection_
->Embed(BuildViewId(1, 1), kTestServiceURL
));
1165 // Connecting to 1,2 should succeed and end up in connection2.
1167 ASSERT_TRUE(connection_
->Embed(BuildViewId(1, 2), kTestServiceURL
));
1168 connection2_
->DoRunLoopUntilChangesCount(1);
1169 const Changes
changes(ChangesToDescription1(connection2_
->changes()));
1170 ASSERT_EQ(1u, changes
.size());
1171 EXPECT_EQ("OnEmbed creator=mojo:test_url", changes
[0]);
1172 EXPECT_EQ("[view=1,2 parent=null]",
1173 ChangeViewDescription(connection2_
->changes()));
1177 TEST_F(ViewManagerTest
, OnViewInput
) {
1178 ASSERT_TRUE(connection_
->CreateView(BuildViewId(1, 1)));
1179 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1181 // Dispatch an event to the view and verify its received.
1183 EventPtr
event(Event::New());
1184 event
->action
= static_cast<EventType
>(1);
1185 connection_
->view_manager()->DispatchOnViewInputEvent(BuildViewId(1, 1),
1187 connection2_
->DoRunLoopUntilChangesCount(1);
1188 const Changes
changes(ChangesToDescription1(connection2_
->changes()));
1189 ASSERT_EQ(1u, changes
.size());
1190 EXPECT_EQ("InputEvent view=1,1 event_action=1", changes
[0]);
1194 TEST_F(ViewManagerTest
, EmbedWithSameViewId
) {
1195 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1197 ASSERT_NO_FATAL_FAILURE(
1198 EstablishThirdConnection(connection_
, BuildViewId(1, 1)));
1200 // Connection2 should have been told the view was deleted.
1202 connection2_
->DoRunLoopUntilChangesCount(1);
1203 const Changes
changes(ChangesToDescription1(connection2_
->changes()));
1204 ASSERT_EQ(1u, changes
.size());
1205 EXPECT_EQ("ViewDeleted view=1,1", changes
[0]);
1208 // Connection2 has no root. Verify it can't see view 1,1 anymore.
1210 std::vector
<TestView
> views
;
1211 connection2_
->GetViewTree(BuildViewId(1, 1), &views
);
1212 EXPECT_TRUE(views
.empty());
1216 TEST_F(ViewManagerTest
, EmbedWithSameViewId2
) {
1217 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1219 ASSERT_NO_FATAL_FAILURE(
1220 EstablishThirdConnection(connection_
, BuildViewId(1, 1)));
1222 // Connection2 should have been told the view was deleted.
1223 connection2_
->DoRunLoopUntilChangesCount(1);
1224 connection2_
->ClearChanges();
1226 // Create a view in the third connection and parent it to the root.
1227 ASSERT_TRUE(connection3_
->CreateView(BuildViewId(3, 1)));
1228 ASSERT_TRUE(connection3_
->AddView(BuildViewId(1, 1), BuildViewId(3, 1)));
1230 // Connection 1 should have been told about the add (it owns the view).
1232 connection_
->DoRunLoopUntilChangesCount(1);
1233 const Changes
changes(ChangesToDescription1(connection_
->changes()));
1234 ASSERT_EQ(1u, changes
.size());
1235 EXPECT_EQ("HierarchyChanged view=3,1 new_parent=1,1 old_parent=null",
1239 // Embed 1,1 back in connection 2.
1241 // 2 should be told about the new embed.
1242 ASSERT_TRUE(connection_
->Embed(BuildViewId(1, 1), kTestServiceURL
));
1243 connection2_
->DoRunLoopUntilChangesCount(1);
1244 const std::vector
<Change
>& changes(connection2_
->changes());
1245 ASSERT_EQ(1u, changes
.size());
1246 EXPECT_EQ("OnEmbed creator=mojo:test_url",
1247 ChangesToDescription1(changes
)[0]);
1248 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes
));
1250 // And 3 should get a delete.
1251 connection3_
->DoRunLoopUntilChangesCount(1);
1252 ASSERT_EQ(1u, connection3_
->changes().size());
1253 EXPECT_EQ("ViewDeleted view=1,1",
1254 ChangesToDescription1(connection3_
->changes())[0]);
1257 // Connection3_ has no root. Verify it can't see view 1,1 anymore.
1259 std::vector
<TestView
> views
;
1260 connection3_
->GetViewTree(BuildViewId(1, 1), &views
);
1261 EXPECT_TRUE(views
.empty());
1264 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as
1265 // connection3_ can no longer see 1,1.
1267 std::vector
<TestView
> views
;
1268 connection_
->GetViewTree(BuildViewId(1, 1), &views
);
1269 ASSERT_EQ(1u, views
.size());
1270 EXPECT_EQ("view=1,1 parent=null", views
[0].ToString());
1273 // Verify connection3_ can still see the view it created 3,1.
1275 std::vector
<TestView
> views
;
1276 connection3_
->GetViewTree(BuildViewId(3, 1), &views
);
1277 ASSERT_EQ(1u, views
.size());
1278 EXPECT_EQ("view=3,1 parent=null", views
[0].ToString());
1282 // TODO(sky): add coverage of test that destroys connections and ensures other
1283 // connections get deletion notification.
1285 // TODO(sky): need to better track changes to initial connection. For example,
1286 // that SetBounsdViews/AddView and the like don't result in messages to the
1287 // originating connection.
1289 } // namespace service