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.
5 #include "base/logging.h"
6 #include "components/view_manager/public/cpp/tests/view_manager_test_base.h"
7 #include "components/view_manager/public/cpp/view_observer.h"
8 #include "components/view_manager/public/cpp/view_tree_connection.h"
9 #include "components/view_manager/public/cpp/view_tree_delegate.h"
10 #include "mojo/application/public/cpp/application_connection.h"
11 #include "mojo/application/public/cpp/application_impl.h"
12 #include "mojo/application/public/cpp/application_test_base.h"
13 #include "ui/mojo/geometry/geometry_util.h"
19 class BoundsChangeObserver
: public ViewObserver
{
21 explicit BoundsChangeObserver(View
* view
) : view_(view
) {
22 view_
->AddObserver(this);
24 ~BoundsChangeObserver() override
{ view_
->RemoveObserver(this); }
27 // Overridden from ViewObserver:
28 void OnViewBoundsChanged(View
* view
,
29 const Rect
& old_bounds
,
30 const Rect
& new_bounds
) override
{
31 DCHECK_EQ(view
, view_
);
32 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
37 MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver
);
40 // Wait until the bounds of the supplied view change; returns false on timeout.
41 bool WaitForBoundsToChange(View
* view
) {
42 BoundsChangeObserver
observer(view
);
43 return ViewManagerTestBase::DoRunLoopWithTimeout();
46 // Spins a run loop until the tree beginning at |root| has |tree_size| views
47 // (including |root|).
48 class TreeSizeMatchesObserver
: public ViewObserver
{
50 TreeSizeMatchesObserver(View
* tree
, size_t tree_size
)
51 : tree_(tree
), tree_size_(tree_size
) {
52 tree_
->AddObserver(this);
54 ~TreeSizeMatchesObserver() override
{ tree_
->RemoveObserver(this); }
56 bool IsTreeCorrectSize() { return CountViews(tree_
) == tree_size_
; }
59 // Overridden from ViewObserver:
60 void OnTreeChanged(const TreeChangeParams
& params
) override
{
61 if (IsTreeCorrectSize())
62 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
65 size_t CountViews(const View
* view
) const {
67 View::Children::const_iterator it
= view
->children().begin();
68 for (; it
!= view
->children().end(); ++it
)
69 count
+= CountViews(*it
);
76 MOJO_DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver
);
79 // Wait until |view| has |tree_size| descendants; returns false on timeout. The
80 // count includes |view|. For example, if you want to wait for |view| to have
81 // a single child, use a |tree_size| of 2.
82 bool WaitForTreeSizeToMatch(View
* view
, size_t tree_size
) {
83 TreeSizeMatchesObserver
observer(view
, tree_size
);
84 return observer
.IsTreeCorrectSize() ||
85 ViewManagerTestBase::DoRunLoopWithTimeout();
88 class OrderChangeObserver
: public ViewObserver
{
90 OrderChangeObserver(View
* view
) : view_(view
) { view_
->AddObserver(this); }
91 ~OrderChangeObserver() override
{ view_
->RemoveObserver(this); }
94 // Overridden from ViewObserver:
95 void OnViewReordered(View
* view
,
97 OrderDirection direction
) override
{
98 DCHECK_EQ(view
, view_
);
99 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
104 MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver
);
107 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
108 bool WaitForOrderChange(ViewTreeConnection
* connection
, View
* view
) {
109 OrderChangeObserver
observer(view
);
110 return ViewManagerTestBase::DoRunLoopWithTimeout();
113 // Tracks a view's destruction. Query is_valid() for current state.
114 class ViewTracker
: public ViewObserver
{
116 explicit ViewTracker(View
* view
) : view_(view
) { view_
->AddObserver(this); }
117 ~ViewTracker() override
{
119 view_
->RemoveObserver(this);
122 bool is_valid() const { return !!view_
; }
125 // Overridden from ViewObserver:
126 void OnViewDestroyed(View
* view
) override
{
127 DCHECK_EQ(view
, view_
);
133 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker
);
138 // ViewManager -----------------------------------------------------------------
140 // These tests model synchronization of two peer connections to the view manager
141 // service, that are given access to some root view.
143 class ViewManagerTest
: public ViewManagerTestBase
{
147 // Embeds another version of the test app @ view. This runs a run loop until
148 // a response is received, or a timeout. On success the new ViewManager is
150 ViewTreeConnection
* Embed(View
* view
) {
151 most_recent_connection_
= nullptr;
152 ConnectToApplicationAndEmbed(view
);
153 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
155 ViewTreeConnection
* vm
= nullptr;
156 std::swap(vm
, most_recent_connection_
);
160 // Establishes a connection to this application and asks for a
161 // ViewTreeClient. The ViewTreeClient is then embedded in |view|. This does
162 // *not* wait for the connection to complete.
163 void ConnectToApplicationAndEmbed(View
* view
) {
164 mojo::URLRequestPtr
request(mojo::URLRequest::New());
165 request
->url
= mojo::String::From(application_impl()->url());
166 scoped_ptr
<ApplicationConnection
> connection
=
167 application_impl()->ConnectToApplication(request
.Pass());
168 mojo::ViewTreeClientPtr client
;
169 connection
->ConnectToService(&client
);
170 view
->Embed(client
.Pass());
174 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTest
);
177 TEST_F(ViewManagerTest
, RootView
) {
178 ASSERT_NE(nullptr, window_manager());
179 EXPECT_NE(nullptr, window_manager()->GetRoot());
182 TEST_F(ViewManagerTest
, Embed
) {
183 View
* view
= window_manager()->CreateView();
184 ASSERT_NE(nullptr, view
);
185 view
->SetVisible(true);
186 window_manager()->GetRoot()->AddChild(view
);
187 ViewTreeConnection
* embedded
= Embed(view
);
188 ASSERT_NE(nullptr, embedded
);
190 View
* view_in_embedded
= embedded
->GetRoot();
191 ASSERT_NE(nullptr, view_in_embedded
);
192 EXPECT_EQ(view
->id(), view_in_embedded
->id());
193 EXPECT_EQ(nullptr, view_in_embedded
->parent());
194 EXPECT_TRUE(view_in_embedded
->children().empty());
197 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see
199 TEST_F(ViewManagerTest
, EmbeddedDoesntSeeChild
) {
200 View
* view
= window_manager()->CreateView();
201 ASSERT_NE(nullptr, view
);
202 view
->SetVisible(true);
203 window_manager()->GetRoot()->AddChild(view
);
204 View
* nested
= window_manager()->CreateView();
205 ASSERT_NE(nullptr, nested
);
206 nested
->SetVisible(true);
207 view
->AddChild(nested
);
209 ViewTreeConnection
* embedded
= Embed(view
);
210 ASSERT_NE(nullptr, embedded
);
211 View
* view_in_embedded
= embedded
->GetRoot();
212 EXPECT_EQ(view
->id(), view_in_embedded
->id());
213 EXPECT_EQ(nullptr, view_in_embedded
->parent());
214 EXPECT_TRUE(view_in_embedded
->children().empty());
217 // TODO(beng): write a replacement test for the one that once existed here:
218 // This test validates the following scenario:
219 // - a view originating from one connection
220 // - a view originating from a second connection
221 // + the connection originating the view is destroyed
222 // -> the view should still exist (since the second connection is live) but
223 // should be disconnected from any views.
224 // http://crbug.com/396300
226 // TODO(beng): The new test should validate the scenario as described above
227 // except that the second connection still has a valid tree.
229 // Verifies that bounds changes applied to a view hierarchy in one connection
230 // are reflected to another.
231 TEST_F(ViewManagerTest
, SetBounds
) {
232 View
* view
= window_manager()->CreateView();
233 view
->SetVisible(true);
234 window_manager()->GetRoot()->AddChild(view
);
235 ViewTreeConnection
* embedded
= Embed(view
);
236 ASSERT_NE(nullptr, embedded
);
238 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
239 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
242 rect
.width
= rect
.height
= 100;
243 view
->SetBounds(rect
);
244 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
245 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
248 // Verifies that bounds changes applied to a view owned by a different
249 // connection are refused.
250 TEST_F(ViewManagerTest
, SetBoundsSecurity
) {
251 View
* view
= window_manager()->CreateView();
252 view
->SetVisible(true);
253 window_manager()->GetRoot()->AddChild(view
);
254 ViewTreeConnection
* embedded
= Embed(view
);
255 ASSERT_NE(nullptr, embedded
);
257 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
261 view
->SetBounds(rect
);
262 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
266 view_in_embedded
->SetBounds(rect
);
267 // Bounds change should have been rejected.
268 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
271 // Verifies that a view can only be destroyed by the connection that created it.
272 TEST_F(ViewManagerTest
, DestroySecurity
) {
273 View
* view
= window_manager()->CreateView();
274 view
->SetVisible(true);
275 window_manager()->GetRoot()->AddChild(view
);
276 ViewTreeConnection
* embedded
= Embed(view
);
277 ASSERT_NE(nullptr, embedded
);
279 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
281 ViewTracker
tracker2(view_in_embedded
);
282 view_in_embedded
->Destroy();
283 // View should not have been destroyed.
284 EXPECT_TRUE(tracker2
.is_valid());
286 ViewTracker
tracker1(view
);
288 EXPECT_FALSE(tracker1
.is_valid());
291 TEST_F(ViewManagerTest
, MultiRoots
) {
292 View
* view1
= window_manager()->CreateView();
293 view1
->SetVisible(true);
294 window_manager()->GetRoot()->AddChild(view1
);
295 View
* view2
= window_manager()->CreateView();
296 view2
->SetVisible(true);
297 window_manager()->GetRoot()->AddChild(view2
);
298 ViewTreeConnection
* embedded1
= Embed(view1
);
299 ASSERT_NE(nullptr, embedded1
);
300 ViewTreeConnection
* embedded2
= Embed(view2
);
301 ASSERT_NE(nullptr, embedded2
);
302 EXPECT_NE(embedded1
, embedded2
);
305 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
306 // Debug and re-enable this.
307 TEST_F(ViewManagerTest
, DISABLED_Reorder
) {
308 View
* view1
= window_manager()->CreateView();
309 view1
->SetVisible(true);
310 window_manager()->GetRoot()->AddChild(view1
);
312 ViewTreeConnection
* embedded
= Embed(view1
);
313 ASSERT_NE(nullptr, embedded
);
315 View
* view11
= embedded
->CreateView();
316 view11
->SetVisible(true);
317 embedded
->GetRoot()->AddChild(view11
);
318 View
* view12
= embedded
->CreateView();
319 view12
->SetVisible(true);
320 embedded
->GetRoot()->AddChild(view12
);
322 View
* root_in_embedded
= embedded
->GetRoot();
325 ASSERT_TRUE(WaitForTreeSizeToMatch(root_in_embedded
, 3u));
326 view11
->MoveToFront();
327 ASSERT_TRUE(WaitForOrderChange(embedded
, root_in_embedded
));
329 EXPECT_EQ(root_in_embedded
->children().front(),
330 embedded
->GetViewById(view12
->id()));
331 EXPECT_EQ(root_in_embedded
->children().back(),
332 embedded
->GetViewById(view11
->id()));
336 view11
->MoveToBack();
337 ASSERT_TRUE(WaitForOrderChange(embedded
,
338 embedded
->GetViewById(view11
->id())));
340 EXPECT_EQ(root_in_embedded
->children().front(),
341 embedded
->GetViewById(view11
->id()));
342 EXPECT_EQ(root_in_embedded
->children().back(),
343 embedded
->GetViewById(view12
->id()));
349 class VisibilityChangeObserver
: public ViewObserver
{
351 explicit VisibilityChangeObserver(View
* view
) : view_(view
) {
352 view_
->AddObserver(this);
354 ~VisibilityChangeObserver() override
{ view_
->RemoveObserver(this); }
357 // Overridden from ViewObserver:
358 void OnViewVisibilityChanged(View
* view
) override
{
359 EXPECT_EQ(view
, view_
);
360 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
365 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver
);
370 TEST_F(ViewManagerTest
, Visible
) {
371 View
* view1
= window_manager()->CreateView();
372 view1
->SetVisible(true);
373 window_manager()->GetRoot()->AddChild(view1
);
375 // Embed another app and verify initial state.
376 ViewTreeConnection
* embedded
= Embed(view1
);
377 ASSERT_NE(nullptr, embedded
);
378 ASSERT_NE(nullptr, embedded
->GetRoot());
379 View
* embedded_root
= embedded
->GetRoot();
380 EXPECT_TRUE(embedded_root
->visible());
381 EXPECT_TRUE(embedded_root
->IsDrawn());
383 // Change the visible state from the first connection and verify its mirrored
384 // correctly to the embedded app.
386 VisibilityChangeObserver
observer(embedded_root
);
387 view1
->SetVisible(false);
388 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
391 EXPECT_FALSE(view1
->visible());
392 EXPECT_FALSE(view1
->IsDrawn());
394 EXPECT_FALSE(embedded_root
->visible());
395 EXPECT_FALSE(embedded_root
->IsDrawn());
397 // Make the node visible again.
399 VisibilityChangeObserver
observer(embedded_root
);
400 view1
->SetVisible(true);
401 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
404 EXPECT_TRUE(view1
->visible());
405 EXPECT_TRUE(view1
->IsDrawn());
407 EXPECT_TRUE(embedded_root
->visible());
408 EXPECT_TRUE(embedded_root
->IsDrawn());
413 class DrawnChangeObserver
: public ViewObserver
{
415 explicit DrawnChangeObserver(View
* view
) : view_(view
) {
416 view_
->AddObserver(this);
418 ~DrawnChangeObserver() override
{ view_
->RemoveObserver(this); }
421 // Overridden from ViewObserver:
422 void OnViewDrawnChanged(View
* view
) override
{
423 EXPECT_EQ(view
, view_
);
424 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
429 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver
);
434 TEST_F(ViewManagerTest
, Drawn
) {
435 View
* view1
= window_manager()->CreateView();
436 view1
->SetVisible(true);
437 window_manager()->GetRoot()->AddChild(view1
);
439 // Embed another app and verify initial state.
440 ViewTreeConnection
* embedded
= Embed(view1
);
441 ASSERT_NE(nullptr, embedded
);
442 ASSERT_NE(nullptr, embedded
->GetRoot());
443 View
* embedded_root
= embedded
->GetRoot();
444 EXPECT_TRUE(embedded_root
->visible());
445 EXPECT_TRUE(embedded_root
->IsDrawn());
447 // Change the visibility of the root, this should propagate a drawn state
448 // change to |embedded|.
450 DrawnChangeObserver
observer(embedded_root
);
451 window_manager()->GetRoot()->SetVisible(false);
452 ASSERT_TRUE(DoRunLoopWithTimeout());
455 EXPECT_TRUE(view1
->visible());
456 EXPECT_FALSE(view1
->IsDrawn());
458 EXPECT_TRUE(embedded_root
->visible());
459 EXPECT_FALSE(embedded_root
->IsDrawn());
462 // TODO(beng): tests for view event dispatcher.
463 // - verify that we see events for all views.
467 class FocusChangeObserver
: public ViewObserver
{
469 explicit FocusChangeObserver(View
* view
)
470 : view_(view
), last_gained_focus_(nullptr), last_lost_focus_(nullptr) {
471 view_
->AddObserver(this);
473 ~FocusChangeObserver() override
{ view_
->RemoveObserver(this); }
475 View
* last_gained_focus() { return last_gained_focus_
; }
477 View
* last_lost_focus() { return last_lost_focus_
; }
480 // Overridden from ViewObserver.
481 void OnViewFocusChanged(View
* gained_focus
, View
* lost_focus
) override
{
482 EXPECT_TRUE(!gained_focus
|| gained_focus
->HasFocus());
483 EXPECT_FALSE(lost_focus
&& lost_focus
->HasFocus());
484 last_gained_focus_
= gained_focus
;
485 last_lost_focus_
= lost_focus
;
486 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
490 View
* last_gained_focus_
;
491 View
* last_lost_focus_
;
493 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver
);
498 TEST_F(ViewManagerTest
, Focus
) {
499 View
* view1
= window_manager()->CreateView();
500 view1
->SetVisible(true);
501 window_manager()->GetRoot()->AddChild(view1
);
503 ViewTreeConnection
* embedded
= Embed(view1
);
504 ASSERT_NE(nullptr, embedded
);
505 View
* view11
= embedded
->CreateView();
506 view11
->SetVisible(true);
507 embedded
->GetRoot()->AddChild(view11
);
509 // TODO(alhaad): Figure out why switching focus between views from different
510 // connections is causing the tests to crash and add tests for that.
512 View
* embedded_root
= embedded
->GetRoot();
513 FocusChangeObserver
observer(embedded_root
);
514 embedded_root
->SetFocus();
515 ASSERT_TRUE(DoRunLoopWithTimeout());
516 ASSERT_NE(nullptr, observer
.last_gained_focus());
517 EXPECT_EQ(embedded_root
->id(), observer
.last_gained_focus()->id());
520 FocusChangeObserver
observer(view11
);
522 ASSERT_TRUE(DoRunLoopWithTimeout());
523 ASSERT_NE(nullptr, observer
.last_gained_focus());
524 ASSERT_NE(nullptr, observer
.last_lost_focus());
525 EXPECT_EQ(view11
->id(), observer
.last_gained_focus()->id());
526 EXPECT_EQ(embedded
->GetRoot()->id(), observer
.last_lost_focus()->id());
529 // Add an observer on the View that loses focus, and make sure the observer
530 // sees the right values.
531 FocusChangeObserver
observer(view11
);
532 embedded
->GetRoot()->SetFocus();
533 ASSERT_TRUE(DoRunLoopWithTimeout());
534 ASSERT_NE(nullptr, observer
.last_gained_focus());
535 ASSERT_NE(nullptr, observer
.last_lost_focus());
536 EXPECT_EQ(view11
->id(), observer
.last_lost_focus()->id());
537 EXPECT_EQ(embedded
->GetRoot()->id(), observer
.last_gained_focus()->id());
543 class DestroyedChangedObserver
: public ViewObserver
{
545 DestroyedChangedObserver(ViewManagerTestBase
* test
,
548 : test_(test
), view_(view
), got_destroy_(got_destroy
) {
549 view_
->AddObserver(this);
551 ~DestroyedChangedObserver() override
{
553 view_
->RemoveObserver(this);
557 // Overridden from ViewObserver:
558 void OnViewDestroyed(View
* view
) override
{
559 EXPECT_EQ(view
, view_
);
560 view_
->RemoveObserver(this);
561 *got_destroy_
= true;
564 // We should always get OnViewDestroyed() before OnConnectionLost().
565 EXPECT_FALSE(test_
->view_tree_connection_destroyed());
568 ViewManagerTestBase
* test_
;
572 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver
);
577 // Verifies deleting a ViewManager sends the right notifications.
578 TEST_F(ViewManagerTest
, DeleteViewManager
) {
579 View
* view
= window_manager()->CreateView();
580 ASSERT_NE(nullptr, view
);
581 view
->SetVisible(true);
582 window_manager()->GetRoot()->AddChild(view
);
583 ViewTreeConnection
* connection
= Embed(view
);
584 ASSERT_TRUE(connection
);
585 bool got_destroy
= false;
586 DestroyedChangedObserver
observer(this, connection
->GetRoot(),
589 EXPECT_TRUE(view_tree_connection_destroyed());
590 EXPECT_TRUE(got_destroy
);
593 // Verifies two Embed()s in the same view trigger deletion of the first
595 TEST_F(ViewManagerTest
, DisconnectTriggersDelete
) {
596 View
* view
= window_manager()->CreateView();
597 ASSERT_NE(nullptr, view
);
598 view
->SetVisible(true);
599 window_manager()->GetRoot()->AddChild(view
);
600 ViewTreeConnection
* connection
= Embed(view
);
601 EXPECT_NE(connection
, window_manager());
602 View
* embedded_view
= connection
->CreateView();
603 // Embed again, this should trigger disconnect and deletion of connection.
605 DestroyedChangedObserver
observer(this, embedded_view
, &got_destroy
);
606 EXPECT_FALSE(view_tree_connection_destroyed());
608 EXPECT_TRUE(view_tree_connection_destroyed());
611 class ViewRemovedFromParentObserver
: public ViewObserver
{
613 explicit ViewRemovedFromParentObserver(View
* view
)
614 : view_(view
), was_removed_(false) {
615 view_
->AddObserver(this);
617 ~ViewRemovedFromParentObserver() override
{ view_
->RemoveObserver(this); }
619 bool was_removed() const { return was_removed_
; }
622 // Overridden from ViewObserver:
623 void OnTreeChanged(const TreeChangeParams
& params
) override
{
624 if (params
.target
== view_
&& !params
.new_parent
)
631 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewRemovedFromParentObserver
);
634 TEST_F(ViewManagerTest
, EmbedRemovesChildren
) {
635 View
* view1
= window_manager()->CreateView();
636 View
* view2
= window_manager()->CreateView();
637 window_manager()->GetRoot()->AddChild(view1
);
638 view1
->AddChild(view2
);
640 ViewRemovedFromParentObserver
observer(view2
);
641 ConnectToApplicationAndEmbed(view1
);
642 EXPECT_TRUE(observer
.was_removed());
643 EXPECT_EQ(nullptr, view2
->parent());
644 EXPECT_TRUE(view1
->children().empty());
646 // Run the message loop so the Embed() call above completes. Without this
647 // we may end up reconnecting to the test and rerunning the test, which is
648 // problematic since the other services don't shut down.
649 ASSERT_TRUE(DoRunLoopWithTimeout());
654 class DestroyObserver
: public ViewObserver
{
656 DestroyObserver(ViewManagerTestBase
* test
,
657 ViewTreeConnection
* connection
,
659 : test_(test
), got_destroy_(got_destroy
) {
660 connection
->GetRoot()->AddObserver(this);
662 ~DestroyObserver() override
{}
665 // Overridden from ViewObserver:
666 void OnViewDestroyed(View
* view
) override
{
667 *got_destroy_
= true;
668 view
->RemoveObserver(this);
670 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
671 EXPECT_FALSE(test_
->view_tree_connection_destroyed());
673 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
676 ViewManagerTestBase
* test_
;
679 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyObserver
);
684 // Verifies deleting a View that is the root of another connection notifies
685 // observers in the right order (OnViewDestroyed() before
686 // OnViewManagerDestroyed()).
687 TEST_F(ViewManagerTest
, ViewManagerDestroyedAfterRootObserver
) {
688 View
* embed_view
= window_manager()->CreateView();
689 window_manager()->GetRoot()->AddChild(embed_view
);
691 ViewTreeConnection
* embedded_connection
= Embed(embed_view
);
693 bool got_destroy
= false;
694 DestroyObserver
observer(this, embedded_connection
, &got_destroy
);
695 // Delete the view |embedded_connection| is embedded in. This is async,
696 // but will eventually trigger deleting |embedded_connection|.
697 embed_view
->Destroy();
698 EXPECT_TRUE(DoRunLoopWithTimeout());
699 EXPECT_TRUE(got_destroy
);
702 // Verifies an embed root sees views created beneath it from another
704 TEST_F(ViewManagerTest
, EmbedRootSeesHierarchyChanged
) {
705 View
* embed_view
= window_manager()->CreateView();
706 window_manager()->GetRoot()->AddChild(embed_view
);
708 embed_view
->SetAccessPolicy(ViewTree::ACCESS_POLICY_EMBED_ROOT
);
709 ViewTreeConnection
* vm2
= Embed(embed_view
);
710 View
* vm2_v1
= vm2
->CreateView();
711 vm2
->GetRoot()->AddChild(vm2_v1
);
713 ViewTreeConnection
* vm3
= Embed(vm2_v1
);
714 View
* vm3_v1
= vm3
->CreateView();
715 vm3
->GetRoot()->AddChild(vm3_v1
);
717 // As |vm2| is an embed root it should get notified about |vm3_v1|.
718 ASSERT_TRUE(WaitForTreeSizeToMatch(vm2_v1
, 2));
721 TEST_F(ViewManagerTest
, EmbedFromEmbedRoot
) {
722 View
* embed_view
= window_manager()->CreateView();
723 window_manager()->GetRoot()->AddChild(embed_view
);
725 embed_view
->SetAccessPolicy(ViewTree::ACCESS_POLICY_EMBED_ROOT
);
726 ViewTreeConnection
* vm2
= Embed(embed_view
);
727 View
* vm2_v1
= vm2
->CreateView();
728 vm2
->GetRoot()->AddChild(vm2_v1
);
730 ViewTreeConnection
* vm3
= Embed(vm2_v1
);
731 View
* vm3_v1
= vm3
->CreateView();
732 vm3
->GetRoot()->AddChild(vm3_v1
);
734 // As |vm2| is an embed root it should get notified about |vm3_v1|.
735 ASSERT_TRUE(WaitForTreeSizeToMatch(vm2_v1
, 2));
737 // Embed() from vm2 in vm3_v1. This is allowed as vm2 is an embed root.
738 ASSERT_EQ(1u, vm2_v1
->children().size());
739 View
* vm3_v1_in_vm2
= vm2_v1
->children()[0];
740 ASSERT_TRUE(Embed(vm3_v1_in_vm2
));