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 "components/view_manager/public/cpp/view_manager.h"
7 #include "base/logging.h"
8 #include "components/view_manager/public/cpp/lib/view_manager_client_impl.h"
9 #include "components/view_manager/public/cpp/tests/view_manager_test_base.h"
10 #include "components/view_manager/public/cpp/view_manager_client_factory.h"
11 #include "components/view_manager/public/cpp/view_manager_delegate.h"
12 #include "components/view_manager/public/cpp/view_manager_init.h"
13 #include "components/view_manager/public/cpp/view_observer.h"
14 #include "mojo/application/public/cpp/application_connection.h"
15 #include "mojo/application/public/cpp/application_impl.h"
16 #include "mojo/application/public/cpp/application_test_base.h"
17 #include "ui/mojo/geometry/geometry_util.h"
23 class BoundsChangeObserver
: public ViewObserver
{
25 explicit BoundsChangeObserver(View
* view
) : view_(view
) {
26 view_
->AddObserver(this);
28 ~BoundsChangeObserver() override
{ view_
->RemoveObserver(this); }
31 // Overridden from ViewObserver:
32 void OnViewBoundsChanged(View
* view
,
33 const Rect
& old_bounds
,
34 const Rect
& new_bounds
) override
{
35 DCHECK_EQ(view
, view_
);
36 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
41 MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver
);
44 // Wait until the bounds of the supplied view change; returns false on timeout.
45 bool WaitForBoundsToChange(View
* view
) {
46 BoundsChangeObserver
observer(view
);
47 return ViewManagerTestBase::DoRunLoopWithTimeout();
50 // Increments the width of |view| and waits for a bounds change in |other_vm|s
52 bool IncrementWidthAndWaitForChange(View
* view
, ViewManager
* other_vm
) {
53 mojo::Rect bounds
= view
->bounds();
55 view
->SetBounds(bounds
);
56 View
* view_in_vm
= other_vm
->GetRoot();
57 if (view_in_vm
== view
|| view_in_vm
->id() != view
->id())
59 return WaitForBoundsToChange(view_in_vm
);
62 // Spins a run loop until the tree beginning at |root| has |tree_size| views
63 // (including |root|).
64 class TreeSizeMatchesObserver
: public ViewObserver
{
66 TreeSizeMatchesObserver(View
* tree
, size_t tree_size
)
67 : tree_(tree
), tree_size_(tree_size
) {
68 tree_
->AddObserver(this);
70 ~TreeSizeMatchesObserver() override
{ tree_
->RemoveObserver(this); }
72 bool IsTreeCorrectSize() { return CountViews(tree_
) == tree_size_
; }
75 // Overridden from ViewObserver:
76 void OnTreeChanged(const TreeChangeParams
& params
) override
{
77 if (IsTreeCorrectSize())
78 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
81 size_t CountViews(const View
* view
) const {
83 View::Children::const_iterator it
= view
->children().begin();
84 for (; it
!= view
->children().end(); ++it
)
85 count
+= CountViews(*it
);
92 MOJO_DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver
);
95 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
96 bool WaitForTreeSizeToMatch(View
* view
, size_t tree_size
) {
97 TreeSizeMatchesObserver
observer(view
, tree_size
);
98 return observer
.IsTreeCorrectSize() ||
99 ViewManagerTestBase::DoRunLoopWithTimeout();
102 class OrderChangeObserver
: public ViewObserver
{
104 OrderChangeObserver(View
* view
) : view_(view
) { view_
->AddObserver(this); }
105 ~OrderChangeObserver() override
{ view_
->RemoveObserver(this); }
108 // Overridden from ViewObserver:
109 void OnViewReordered(View
* view
,
111 OrderDirection direction
) override
{
112 DCHECK_EQ(view
, view_
);
113 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
118 MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver
);
121 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
122 bool WaitForOrderChange(ViewManager
* view_manager
, View
* view
) {
123 OrderChangeObserver
observer(view
);
124 return ViewManagerTestBase::DoRunLoopWithTimeout();
127 // Tracks a view's destruction. Query is_valid() for current state.
128 class ViewTracker
: public ViewObserver
{
130 explicit ViewTracker(View
* view
) : view_(view
) { view_
->AddObserver(this); }
131 ~ViewTracker() override
{
133 view_
->RemoveObserver(this);
136 bool is_valid() const { return !!view_
; }
139 // Overridden from ViewObserver:
140 void OnViewDestroyed(View
* view
) override
{
141 DCHECK_EQ(view
, view_
);
147 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker
);
152 // ViewManager -----------------------------------------------------------------
154 // These tests model synchronization of two peer connections to the view manager
155 // service, that are given access to some root view.
157 class ViewManagerTest
: public ViewManagerTestBase
{
160 : on_will_embed_count_(0u), on_will_embed_return_value_(true) {}
162 void clear_on_will_embed_count() { on_will_embed_count_
= 0u; }
163 size_t on_will_embed_count() const { return on_will_embed_count_
; }
165 void set_on_will_embed_return_value(bool value
) {
166 on_will_embed_return_value_
= value
;
169 // Embeds another version of the test app @ view. This runs a run loop until
170 // a response is received, or a timeout. On success the new ViewManager is
172 ViewManager
* Embed(View
* view
) {
173 return EmbedImpl(view
, EmbedType::NO_REEMBED
);
176 // Same as Embed(), but uses EmbedAllowingReembed().
177 ViewManager
* EmbedAllowingReembed(View
* view
) {
178 return EmbedImpl(view
, EmbedType::ALLOW_REEMBED
);
181 // Establishes a connection to this application and asks for a
182 // ViewManagerClient. The ViewManagerClient is then embedded in |view|.
183 // This does *not* wait for the connection to complete.
184 void ConnectToApplicationAndEmbed(View
* view
) {
185 mojo::URLRequestPtr
request(mojo::URLRequest::New());
186 request
->url
= mojo::String::From(application_impl()->url());
187 ApplicationConnection
* connection
=
188 application_impl()->ConnectToApplication(request
.Pass());
189 mojo::ViewManagerClientPtr client
;
190 connection
->ConnectToService(&client
);
191 view
->Embed(client
.Pass());
194 // Overridden from ViewManagerDelegate:
195 void OnEmbedForDescendant(View
* view
,
196 mojo::URLRequestPtr request
,
197 mojo::ViewManagerClientPtr
* client
) override
{
198 on_will_embed_count_
++;
199 if (on_will_embed_return_value_
) {
200 ApplicationConnection
* connection
=
201 application_impl()->ConnectToApplication(request
.Pass());
202 connection
->ConnectToService(client
);
204 EXPECT_TRUE(QuitRunLoop());
209 enum class EmbedType
{
214 ViewManager
* EmbedImpl(View
* view
, EmbedType type
) {
215 most_recent_view_manager_
= nullptr;
216 if (type
== EmbedType::ALLOW_REEMBED
) {
217 mojo::URLRequestPtr
request(mojo::URLRequest::New());
218 request
->url
= mojo::String::From(application_impl()->url());
219 view
->EmbedAllowingReembed(request
.Pass());
221 ConnectToApplicationAndEmbed(view
);
223 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
225 ViewManager
* vm
= nullptr;
226 std::swap(vm
, most_recent_view_manager_
);
230 // Number of times OnWillEmbed() has been called.
231 size_t on_will_embed_count_
;
233 // Value OnWillEmbed() should return.
234 bool on_will_embed_return_value_
;
236 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTest
);
239 TEST_F(ViewManagerTest
, RootView
) {
240 ASSERT_NE(nullptr, window_manager());
241 EXPECT_NE(nullptr, window_manager()->GetRoot());
244 TEST_F(ViewManagerTest
, Embed
) {
245 View
* view
= window_manager()->CreateView();
246 ASSERT_NE(nullptr, view
);
247 view
->SetVisible(true);
248 window_manager()->GetRoot()->AddChild(view
);
249 ViewManager
* embedded
= Embed(view
);
250 ASSERT_NE(nullptr, embedded
);
252 View
* view_in_embedded
= embedded
->GetRoot();
253 ASSERT_NE(nullptr, view_in_embedded
);
254 EXPECT_EQ(view
->id(), view_in_embedded
->id());
255 EXPECT_EQ(nullptr, view_in_embedded
->parent());
256 EXPECT_TRUE(view_in_embedded
->children().empty());
259 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see
261 TEST_F(ViewManagerTest
, EmbeddedDoesntSeeChild
) {
262 View
* view
= window_manager()->CreateView();
263 ASSERT_NE(nullptr, view
);
264 view
->SetVisible(true);
265 window_manager()->GetRoot()->AddChild(view
);
266 View
* nested
= window_manager()->CreateView();
267 ASSERT_NE(nullptr, nested
);
268 nested
->SetVisible(true);
269 view
->AddChild(nested
);
271 ViewManager
* embedded
= Embed(view
);
272 ASSERT_NE(nullptr, embedded
);
273 View
* view_in_embedded
= embedded
->GetRoot();
274 EXPECT_EQ(view
->id(), view_in_embedded
->id());
275 EXPECT_EQ(nullptr, view_in_embedded
->parent());
276 EXPECT_TRUE(view_in_embedded
->children().empty());
279 // TODO(beng): write a replacement test for the one that once existed here:
280 // This test validates the following scenario:
281 // - a view originating from one connection
282 // - a view originating from a second connection
283 // + the connection originating the view is destroyed
284 // -> the view should still exist (since the second connection is live) but
285 // should be disconnected from any views.
286 // http://crbug.com/396300
288 // TODO(beng): The new test should validate the scenario as described above
289 // except that the second connection still has a valid tree.
291 // Verifies that bounds changes applied to a view hierarchy in one connection
292 // are reflected to another.
293 TEST_F(ViewManagerTest
, SetBounds
) {
294 View
* view
= window_manager()->CreateView();
295 view
->SetVisible(true);
296 window_manager()->GetRoot()->AddChild(view
);
297 ViewManager
* embedded
= Embed(view
);
298 ASSERT_NE(nullptr, embedded
);
300 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
301 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
304 rect
.width
= rect
.height
= 100;
305 view
->SetBounds(rect
);
306 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
307 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
310 // Verifies that bounds changes applied to a view owned by a different
311 // connection are refused.
312 TEST_F(ViewManagerTest
, SetBoundsSecurity
) {
313 View
* view
= window_manager()->CreateView();
314 view
->SetVisible(true);
315 window_manager()->GetRoot()->AddChild(view
);
316 ViewManager
* embedded
= Embed(view
);
317 ASSERT_NE(nullptr, embedded
);
319 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
323 view
->SetBounds(rect
);
324 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
328 view_in_embedded
->SetBounds(rect
);
329 // Bounds change should have been rejected.
330 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
333 // Verifies that a view can only be destroyed by the connection that created it.
334 TEST_F(ViewManagerTest
, DestroySecurity
) {
335 View
* view
= window_manager()->CreateView();
336 view
->SetVisible(true);
337 window_manager()->GetRoot()->AddChild(view
);
338 ViewManager
* embedded
= Embed(view
);
339 ASSERT_NE(nullptr, embedded
);
341 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
343 ViewTracker
tracker2(view_in_embedded
);
344 view_in_embedded
->Destroy();
345 // View should not have been destroyed.
346 EXPECT_TRUE(tracker2
.is_valid());
348 ViewTracker
tracker1(view
);
350 EXPECT_FALSE(tracker1
.is_valid());
353 TEST_F(ViewManagerTest
, MultiRoots
) {
354 View
* view1
= window_manager()->CreateView();
355 view1
->SetVisible(true);
356 window_manager()->GetRoot()->AddChild(view1
);
357 View
* view2
= window_manager()->CreateView();
358 view2
->SetVisible(true);
359 window_manager()->GetRoot()->AddChild(view2
);
360 ViewManager
* embedded1
= Embed(view1
);
361 ASSERT_NE(nullptr, embedded1
);
362 ViewManager
* embedded2
= Embed(view2
);
363 ASSERT_NE(nullptr, embedded2
);
364 EXPECT_NE(embedded1
, embedded2
);
367 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
368 // Debug and re-enable this.
369 TEST_F(ViewManagerTest
, DISABLED_Reorder
) {
370 View
* view1
= window_manager()->CreateView();
371 view1
->SetVisible(true);
372 window_manager()->GetRoot()->AddChild(view1
);
374 ViewManager
* embedded
= Embed(view1
);
375 ASSERT_NE(nullptr, embedded
);
377 View
* view11
= embedded
->CreateView();
378 view11
->SetVisible(true);
379 embedded
->GetRoot()->AddChild(view11
);
380 View
* view12
= embedded
->CreateView();
381 view12
->SetVisible(true);
382 embedded
->GetRoot()->AddChild(view12
);
384 View
* root_in_embedded
= embedded
->GetRoot();
387 ASSERT_TRUE(WaitForTreeSizeToMatch(root_in_embedded
, 3u));
388 view11
->MoveToFront();
389 ASSERT_TRUE(WaitForOrderChange(embedded
, root_in_embedded
));
391 EXPECT_EQ(root_in_embedded
->children().front(),
392 embedded
->GetViewById(view12
->id()));
393 EXPECT_EQ(root_in_embedded
->children().back(),
394 embedded
->GetViewById(view11
->id()));
398 view11
->MoveToBack();
399 ASSERT_TRUE(WaitForOrderChange(embedded
,
400 embedded
->GetViewById(view11
->id())));
402 EXPECT_EQ(root_in_embedded
->children().front(),
403 embedded
->GetViewById(view11
->id()));
404 EXPECT_EQ(root_in_embedded
->children().back(),
405 embedded
->GetViewById(view12
->id()));
411 class VisibilityChangeObserver
: public ViewObserver
{
413 explicit VisibilityChangeObserver(View
* view
) : view_(view
) {
414 view_
->AddObserver(this);
416 ~VisibilityChangeObserver() override
{ view_
->RemoveObserver(this); }
419 // Overridden from ViewObserver:
420 void OnViewVisibilityChanged(View
* view
) override
{
421 EXPECT_EQ(view
, view_
);
422 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
427 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver
);
432 TEST_F(ViewManagerTest
, Visible
) {
433 View
* view1
= window_manager()->CreateView();
434 view1
->SetVisible(true);
435 window_manager()->GetRoot()->AddChild(view1
);
437 // Embed another app and verify initial state.
438 ViewManager
* embedded
= Embed(view1
);
439 ASSERT_NE(nullptr, embedded
);
440 ASSERT_NE(nullptr, embedded
->GetRoot());
441 View
* embedded_root
= embedded
->GetRoot();
442 EXPECT_TRUE(embedded_root
->visible());
443 EXPECT_TRUE(embedded_root
->IsDrawn());
445 // Change the visible state from the first connection and verify its mirrored
446 // correctly to the embedded app.
448 VisibilityChangeObserver
observer(embedded_root
);
449 view1
->SetVisible(false);
450 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
453 EXPECT_FALSE(view1
->visible());
454 EXPECT_FALSE(view1
->IsDrawn());
456 EXPECT_FALSE(embedded_root
->visible());
457 EXPECT_FALSE(embedded_root
->IsDrawn());
459 // Make the node visible again.
461 VisibilityChangeObserver
observer(embedded_root
);
462 view1
->SetVisible(true);
463 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
466 EXPECT_TRUE(view1
->visible());
467 EXPECT_TRUE(view1
->IsDrawn());
469 EXPECT_TRUE(embedded_root
->visible());
470 EXPECT_TRUE(embedded_root
->IsDrawn());
475 class DrawnChangeObserver
: public ViewObserver
{
477 explicit DrawnChangeObserver(View
* view
) : view_(view
) {
478 view_
->AddObserver(this);
480 ~DrawnChangeObserver() override
{ view_
->RemoveObserver(this); }
483 // Overridden from ViewObserver:
484 void OnViewDrawnChanged(View
* view
) override
{
485 EXPECT_EQ(view
, view_
);
486 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
491 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver
);
496 TEST_F(ViewManagerTest
, Drawn
) {
497 View
* view1
= window_manager()->CreateView();
498 view1
->SetVisible(true);
499 window_manager()->GetRoot()->AddChild(view1
);
501 // Embed another app and verify initial state.
502 ViewManager
* embedded
= Embed(view1
);
503 ASSERT_NE(nullptr, embedded
);
504 ASSERT_NE(nullptr, embedded
->GetRoot());
505 View
* embedded_root
= embedded
->GetRoot();
506 EXPECT_TRUE(embedded_root
->visible());
507 EXPECT_TRUE(embedded_root
->IsDrawn());
509 // Change the visibility of the root, this should propagate a drawn state
510 // change to |embedded|.
512 DrawnChangeObserver
observer(embedded_root
);
513 window_manager()->GetRoot()->SetVisible(false);
514 ASSERT_TRUE(DoRunLoopWithTimeout());
517 EXPECT_TRUE(view1
->visible());
518 EXPECT_FALSE(view1
->IsDrawn());
520 EXPECT_TRUE(embedded_root
->visible());
521 EXPECT_FALSE(embedded_root
->IsDrawn());
524 // TODO(beng): tests for view event dispatcher.
525 // - verify that we see events for all views.
529 class FocusChangeObserver
: public ViewObserver
{
531 explicit FocusChangeObserver(View
* view
)
532 : view_(view
), last_gained_focus_(nullptr), last_lost_focus_(nullptr) {
533 view_
->AddObserver(this);
535 ~FocusChangeObserver() override
{ view_
->RemoveObserver(this); }
537 View
* last_gained_focus() { return last_gained_focus_
; }
539 View
* last_lost_focus() { return last_lost_focus_
; }
542 // Overridden from ViewObserver.
543 void OnViewFocusChanged(View
* gained_focus
, View
* lost_focus
) override
{
544 last_gained_focus_
= gained_focus
;
545 last_lost_focus_
= lost_focus
;
546 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
550 View
* last_gained_focus_
;
551 View
* last_lost_focus_
;
553 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver
);
558 TEST_F(ViewManagerTest
, Focus
) {
559 View
* view1
= window_manager()->CreateView();
560 view1
->SetVisible(true);
561 window_manager()->GetRoot()->AddChild(view1
);
563 ViewManager
* embedded
= Embed(view1
);
564 ASSERT_NE(nullptr, embedded
);
565 View
* view11
= embedded
->CreateView();
566 view11
->SetVisible(true);
567 embedded
->GetRoot()->AddChild(view11
);
569 // TODO(alhaad): Figure out why switching focus between views from different
570 // connections is causing the tests to crash and add tests for that.
572 View
* embedded_root
= embedded
->GetRoot();
573 FocusChangeObserver
observer(embedded_root
);
574 embedded_root
->SetFocus();
575 ASSERT_TRUE(DoRunLoopWithTimeout());
576 ASSERT_NE(nullptr, observer
.last_gained_focus());
577 EXPECT_EQ(embedded_root
->id(), observer
.last_gained_focus()->id());
580 FocusChangeObserver
observer(view11
);
582 ASSERT_TRUE(DoRunLoopWithTimeout());
583 ASSERT_NE(nullptr, observer
.last_gained_focus());
584 ASSERT_NE(nullptr, observer
.last_lost_focus());
585 EXPECT_EQ(view11
->id(), observer
.last_gained_focus()->id());
586 EXPECT_EQ(embedded
->GetRoot()->id(), observer
.last_lost_focus()->id());
592 class DestroyedChangedObserver
: public ViewObserver
{
594 DestroyedChangedObserver(ViewManagerTestBase
* test
,
597 : test_(test
), view_(view
), got_destroy_(got_destroy
) {
598 view_
->AddObserver(this);
600 ~DestroyedChangedObserver() override
{
602 view_
->RemoveObserver(this);
606 // Overridden from ViewObserver:
607 void OnViewDestroyed(View
* view
) override
{
608 EXPECT_EQ(view
, view_
);
609 view_
->RemoveObserver(this);
610 *got_destroy_
= true;
613 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
614 EXPECT_FALSE(test_
->view_manager_destroyed());
617 ViewManagerTestBase
* test_
;
621 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver
);
626 // Verifies deleting a ViewManager sends the right notifications.
627 TEST_F(ViewManagerTest
, DeleteViewManager
) {
628 View
* view
= window_manager()->CreateView();
629 ASSERT_NE(nullptr, view
);
630 view
->SetVisible(true);
631 window_manager()->GetRoot()->AddChild(view
);
632 ViewManager
* view_manager
= Embed(view
);
633 ASSERT_TRUE(view_manager
);
634 bool got_destroy
= false;
635 DestroyedChangedObserver
observer(this, view_manager
->GetRoot(),
638 EXPECT_TRUE(view_manager_destroyed());
639 EXPECT_TRUE(got_destroy
);
642 // Verifies two Embed()s in the same view trigger deletion of the first
644 TEST_F(ViewManagerTest
, DisconnectTriggersDelete
) {
645 View
* view
= window_manager()->CreateView();
646 ASSERT_NE(nullptr, view
);
647 view
->SetVisible(true);
648 window_manager()->GetRoot()->AddChild(view
);
649 ViewManager
* view_manager
= Embed(view
);
650 EXPECT_NE(view_manager
, window_manager());
651 View
* embedded_view
= view_manager
->CreateView();
652 // Embed again, this should trigger disconnect and deletion of view_manager.
654 DestroyedChangedObserver
observer(this, embedded_view
, &got_destroy
);
655 EXPECT_FALSE(view_manager_destroyed());
657 EXPECT_TRUE(view_manager_destroyed());
660 class ViewRemovedFromParentObserver
: public ViewObserver
{
662 explicit ViewRemovedFromParentObserver(View
* view
)
663 : view_(view
), was_removed_(false) {
664 view_
->AddObserver(this);
666 ~ViewRemovedFromParentObserver() override
{ view_
->RemoveObserver(this); }
668 bool was_removed() const { return was_removed_
; }
671 // Overridden from ViewObserver:
672 void OnTreeChanged(const TreeChangeParams
& params
) override
{
673 if (params
.target
== view_
&& !params
.new_parent
)
680 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewRemovedFromParentObserver
);
683 TEST_F(ViewManagerTest
, EmbedRemovesChildren
) {
684 View
* view1
= window_manager()->CreateView();
685 View
* view2
= window_manager()->CreateView();
686 window_manager()->GetRoot()->AddChild(view1
);
687 view1
->AddChild(view2
);
689 ViewRemovedFromParentObserver
observer(view2
);
690 ConnectToApplicationAndEmbed(view1
);
691 EXPECT_TRUE(observer
.was_removed());
692 EXPECT_EQ(nullptr, view2
->parent());
693 EXPECT_TRUE(view1
->children().empty());
695 // Run the message loop so the Embed() call above completes. Without this
696 // we may end up reconnecting to the test and rerunning the test, which is
697 // problematic since the other services don't shut down.
698 ASSERT_TRUE(DoRunLoopWithTimeout());
701 TEST_F(ViewManagerTest
, OnWillEmbed
) {
702 window_manager()->SetEmbedRoot();
704 View
* view1
= window_manager()->CreateView();
705 window_manager()->GetRoot()->AddChild(view1
);
707 ViewManager
* view_manager
= EmbedAllowingReembed(view1
);
708 View
* view2
= view_manager
->CreateView();
709 view_manager
->GetRoot()->AddChild(view2
);
711 EmbedAllowingReembed(view2
);
712 EXPECT_EQ(1u, on_will_embed_count());
715 // Verifies Embed() doesn't succeed if OnWillEmbed() returns false.
716 TEST_F(ViewManagerTest
, OnWillEmbedFails
) {
717 window_manager()->SetEmbedRoot();
719 View
* view1
= window_manager()->CreateView();
720 window_manager()->GetRoot()->AddChild(view1
);
722 ViewManager
* view_manager
= Embed(view1
);
723 View
* view2
= view_manager
->CreateView();
724 view_manager
->GetRoot()->AddChild(view2
);
726 clear_on_will_embed_count();
727 set_on_will_embed_return_value(false);
728 mojo::URLRequestPtr
request(mojo::URLRequest::New());
729 request
->url
= application_impl()->url();
730 view2
->EmbedAllowingReembed(request
.Pass());
732 EXPECT_TRUE(DoRunLoopWithTimeout());
733 EXPECT_EQ(1u, on_will_embed_count());
735 // The run loop above quits when OnWillEmbed() returns, which means it's
736 // possible there is still an OnEmbed() message in flight. Sets the bounds of
737 // |view1| and wait for it to the change in |view_manager|, that way we know
738 // |view_manager| has processed all messages for it.
739 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
741 EXPECT_EQ(1u, on_will_embed_count());
744 // Verify an Embed() from an ancestor is not allowed.
745 TEST_F(ViewManagerTest
, ReembedFails
) {
746 window_manager()->SetEmbedRoot();
748 View
* view1
= window_manager()->CreateView();
749 window_manager()->GetRoot()->AddChild(view1
);
751 ViewManager
* view_manager
= Embed(view1
);
752 ASSERT_TRUE(view_manager
);
753 View
* view2
= view_manager
->CreateView();
754 view_manager
->GetRoot()->AddChild(view2
);
757 // Try to embed in view2 from the window_manager. This should fail as the
758 // Embed() didn't grab reembed.
759 View
* view2_in_wm
= window_manager()->GetViewById(view2
->id());
760 ConnectToApplicationAndEmbed(view2_in_wm
);
762 // The Embed() call above returns immediately. To ensure the server has
763 // processed it nudge the bounds and wait for it to be processed.
764 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
766 EXPECT_EQ(nullptr, most_recent_view_manager());
769 // Verify an Embed() from an ancestor is allowed if the ancestor is an embed
770 // root and Embed was done by way of EmbedAllowingReembed().
771 TEST_F(ViewManagerTest
, ReembedSucceeds
) {
772 window_manager()->SetEmbedRoot();
774 View
* view1
= window_manager()->CreateView();
775 window_manager()->GetRoot()->AddChild(view1
);
777 ViewManager
* view_manager
= Embed(view1
);
778 View
* view2
= view_manager
->CreateView();
779 view_manager
->GetRoot()->AddChild(view2
);
780 EmbedAllowingReembed(view2
);
782 View
* view2_in_wm
= window_manager()->GetViewById(view2
->id());
783 ViewManager
* view_manager2
= Embed(view2_in_wm
);
784 ASSERT_TRUE(view_manager2
);
786 // The Embed() call above returns immediately. To ensure the server has
787 // processed it nudge the bounds and wait for it to be processed.
788 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
790 EXPECT_EQ(nullptr, most_recent_view_manager());
795 class DestroyObserver
: public ViewObserver
{
797 DestroyObserver(ViewManagerTestBase
* test
, ViewManager
* vm
, bool* got_destroy
)
798 : test_(test
), got_destroy_(got_destroy
) {
799 vm
->GetRoot()->AddObserver(this);
801 ~DestroyObserver() override
{}
804 // Overridden from ViewObserver:
805 void OnViewDestroyed(View
* view
) override
{
806 *got_destroy_
= true;
807 view
->RemoveObserver(this);
809 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
810 EXPECT_FALSE(test_
->view_manager_destroyed());
812 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
815 ViewManagerTestBase
* test_
;
818 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyObserver
);
823 // Verifies deleting a View that is the root of another connection notifies
824 // observers in the right order (OnViewDestroyed() before
825 // OnViewManagerDestroyed()).
826 TEST_F(ViewManagerTest
, ViewManagerDestroyedAfterRootObserver
) {
827 View
* embed_view
= window_manager()->CreateView();
828 window_manager()->GetRoot()->AddChild(embed_view
);
830 ViewManager
* embedded_view_manager
= Embed(embed_view
);
832 bool got_destroy
= false;
833 DestroyObserver
observer(this, embedded_view_manager
, &got_destroy
);
834 // Delete the view |embedded_view_manager| is embedded in. This is async,
835 // but will eventually trigger deleting |embedded_view_manager|.
836 embed_view
->Destroy();
837 EXPECT_TRUE(DoRunLoopWithTimeout());
838 EXPECT_TRUE(got_destroy
);