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| has |tree_size| descendants; returns false on timeout. The
96 // count includes |view|. For example, if you want to wait for |view| to have
97 // a single child, use a |tree_size| of 2.
98 bool WaitForTreeSizeToMatch(View
* view
, size_t tree_size
) {
99 TreeSizeMatchesObserver
observer(view
, tree_size
);
100 return observer
.IsTreeCorrectSize() ||
101 ViewManagerTestBase::DoRunLoopWithTimeout();
104 class OrderChangeObserver
: public ViewObserver
{
106 OrderChangeObserver(View
* view
) : view_(view
) { view_
->AddObserver(this); }
107 ~OrderChangeObserver() override
{ view_
->RemoveObserver(this); }
110 // Overridden from ViewObserver:
111 void OnViewReordered(View
* view
,
113 OrderDirection direction
) override
{
114 DCHECK_EQ(view
, view_
);
115 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
120 MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver
);
123 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
124 bool WaitForOrderChange(ViewManager
* view_manager
, View
* view
) {
125 OrderChangeObserver
observer(view
);
126 return ViewManagerTestBase::DoRunLoopWithTimeout();
129 // Tracks a view's destruction. Query is_valid() for current state.
130 class ViewTracker
: public ViewObserver
{
132 explicit ViewTracker(View
* view
) : view_(view
) { view_
->AddObserver(this); }
133 ~ViewTracker() override
{
135 view_
->RemoveObserver(this);
138 bool is_valid() const { return !!view_
; }
141 // Overridden from ViewObserver:
142 void OnViewDestroyed(View
* view
) override
{
143 DCHECK_EQ(view
, view_
);
149 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker
);
154 // ViewManager -----------------------------------------------------------------
156 // These tests model synchronization of two peer connections to the view manager
157 // service, that are given access to some root view.
159 class ViewManagerTest
: public ViewManagerTestBase
{
162 : on_will_embed_count_(0u), on_will_embed_return_value_(true) {}
164 void clear_on_will_embed_count() { on_will_embed_count_
= 0u; }
165 size_t on_will_embed_count() const { return on_will_embed_count_
; }
167 void set_on_will_embed_return_value(bool value
) {
168 on_will_embed_return_value_
= value
;
171 // Embeds another version of the test app @ view. This runs a run loop until
172 // a response is received, or a timeout. On success the new ViewManager is
174 ViewManager
* Embed(View
* view
) {
175 return EmbedImpl(view
, EmbedType::NO_REEMBED
);
178 // Same as Embed(), but uses EmbedAllowingReembed().
179 ViewManager
* EmbedAllowingReembed(View
* view
) {
180 return EmbedImpl(view
, EmbedType::ALLOW_REEMBED
);
183 // Establishes a connection to this application and asks for a
184 // ViewManagerClient. The ViewManagerClient is then embedded in |view|.
185 // This does *not* wait for the connection to complete.
186 void ConnectToApplicationAndEmbed(View
* view
) {
187 mojo::URLRequestPtr
request(mojo::URLRequest::New());
188 request
->url
= mojo::String::From(application_impl()->url());
189 scoped_ptr
<ApplicationConnection
> connection
=
190 application_impl()->ConnectToApplication(request
.Pass());
191 mojo::ViewManagerClientPtr client
;
192 connection
->ConnectToService(&client
);
193 view
->Embed(client
.Pass());
196 // Overridden from ViewManagerDelegate:
197 void OnEmbedForDescendant(View
* view
,
198 mojo::URLRequestPtr request
,
199 mojo::ViewManagerClientPtr
* client
) override
{
200 on_will_embed_count_
++;
201 if (on_will_embed_return_value_
) {
202 scoped_ptr
<ApplicationConnection
> connection
=
203 application_impl()->ConnectToApplication(request
.Pass());
204 connection
->ConnectToService(client
);
206 EXPECT_TRUE(QuitRunLoop());
211 enum class EmbedType
{
216 ViewManager
* EmbedImpl(View
* view
, EmbedType type
) {
217 most_recent_view_manager_
= nullptr;
218 if (type
== EmbedType::ALLOW_REEMBED
) {
219 mojo::URLRequestPtr
request(mojo::URLRequest::New());
220 request
->url
= mojo::String::From(application_impl()->url());
221 view
->EmbedAllowingReembed(request
.Pass());
223 ConnectToApplicationAndEmbed(view
);
225 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
227 ViewManager
* vm
= nullptr;
228 std::swap(vm
, most_recent_view_manager_
);
232 // Number of times OnWillEmbed() has been called.
233 size_t on_will_embed_count_
;
235 // Value OnWillEmbed() should return.
236 bool on_will_embed_return_value_
;
238 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTest
);
241 TEST_F(ViewManagerTest
, RootView
) {
242 ASSERT_NE(nullptr, window_manager());
243 EXPECT_NE(nullptr, window_manager()->GetRoot());
246 TEST_F(ViewManagerTest
, Embed
) {
247 View
* view
= window_manager()->CreateView();
248 ASSERT_NE(nullptr, view
);
249 view
->SetVisible(true);
250 window_manager()->GetRoot()->AddChild(view
);
251 ViewManager
* embedded
= Embed(view
);
252 ASSERT_NE(nullptr, embedded
);
254 View
* view_in_embedded
= embedded
->GetRoot();
255 ASSERT_NE(nullptr, view_in_embedded
);
256 EXPECT_EQ(view
->id(), view_in_embedded
->id());
257 EXPECT_EQ(nullptr, view_in_embedded
->parent());
258 EXPECT_TRUE(view_in_embedded
->children().empty());
261 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see
263 TEST_F(ViewManagerTest
, EmbeddedDoesntSeeChild
) {
264 View
* view
= window_manager()->CreateView();
265 ASSERT_NE(nullptr, view
);
266 view
->SetVisible(true);
267 window_manager()->GetRoot()->AddChild(view
);
268 View
* nested
= window_manager()->CreateView();
269 ASSERT_NE(nullptr, nested
);
270 nested
->SetVisible(true);
271 view
->AddChild(nested
);
273 ViewManager
* embedded
= Embed(view
);
274 ASSERT_NE(nullptr, embedded
);
275 View
* view_in_embedded
= embedded
->GetRoot();
276 EXPECT_EQ(view
->id(), view_in_embedded
->id());
277 EXPECT_EQ(nullptr, view_in_embedded
->parent());
278 EXPECT_TRUE(view_in_embedded
->children().empty());
281 // TODO(beng): write a replacement test for the one that once existed here:
282 // This test validates the following scenario:
283 // - a view originating from one connection
284 // - a view originating from a second connection
285 // + the connection originating the view is destroyed
286 // -> the view should still exist (since the second connection is live) but
287 // should be disconnected from any views.
288 // http://crbug.com/396300
290 // TODO(beng): The new test should validate the scenario as described above
291 // except that the second connection still has a valid tree.
293 // Verifies that bounds changes applied to a view hierarchy in one connection
294 // are reflected to another.
295 TEST_F(ViewManagerTest
, SetBounds
) {
296 View
* view
= window_manager()->CreateView();
297 view
->SetVisible(true);
298 window_manager()->GetRoot()->AddChild(view
);
299 ViewManager
* embedded
= Embed(view
);
300 ASSERT_NE(nullptr, embedded
);
302 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
303 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
306 rect
.width
= rect
.height
= 100;
307 view
->SetBounds(rect
);
308 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
309 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
312 // Verifies that bounds changes applied to a view owned by a different
313 // connection are refused.
314 TEST_F(ViewManagerTest
, SetBoundsSecurity
) {
315 View
* view
= window_manager()->CreateView();
316 view
->SetVisible(true);
317 window_manager()->GetRoot()->AddChild(view
);
318 ViewManager
* embedded
= Embed(view
);
319 ASSERT_NE(nullptr, embedded
);
321 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
325 view
->SetBounds(rect
);
326 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
330 view_in_embedded
->SetBounds(rect
);
331 // Bounds change should have been rejected.
332 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
335 // Verifies that a view can only be destroyed by the connection that created it.
336 TEST_F(ViewManagerTest
, DestroySecurity
) {
337 View
* view
= window_manager()->CreateView();
338 view
->SetVisible(true);
339 window_manager()->GetRoot()->AddChild(view
);
340 ViewManager
* embedded
= Embed(view
);
341 ASSERT_NE(nullptr, embedded
);
343 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
345 ViewTracker
tracker2(view_in_embedded
);
346 view_in_embedded
->Destroy();
347 // View should not have been destroyed.
348 EXPECT_TRUE(tracker2
.is_valid());
350 ViewTracker
tracker1(view
);
352 EXPECT_FALSE(tracker1
.is_valid());
355 TEST_F(ViewManagerTest
, MultiRoots
) {
356 View
* view1
= window_manager()->CreateView();
357 view1
->SetVisible(true);
358 window_manager()->GetRoot()->AddChild(view1
);
359 View
* view2
= window_manager()->CreateView();
360 view2
->SetVisible(true);
361 window_manager()->GetRoot()->AddChild(view2
);
362 ViewManager
* embedded1
= Embed(view1
);
363 ASSERT_NE(nullptr, embedded1
);
364 ViewManager
* embedded2
= Embed(view2
);
365 ASSERT_NE(nullptr, embedded2
);
366 EXPECT_NE(embedded1
, embedded2
);
369 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
370 // Debug and re-enable this.
371 TEST_F(ViewManagerTest
, DISABLED_Reorder
) {
372 View
* view1
= window_manager()->CreateView();
373 view1
->SetVisible(true);
374 window_manager()->GetRoot()->AddChild(view1
);
376 ViewManager
* embedded
= Embed(view1
);
377 ASSERT_NE(nullptr, embedded
);
379 View
* view11
= embedded
->CreateView();
380 view11
->SetVisible(true);
381 embedded
->GetRoot()->AddChild(view11
);
382 View
* view12
= embedded
->CreateView();
383 view12
->SetVisible(true);
384 embedded
->GetRoot()->AddChild(view12
);
386 View
* root_in_embedded
= embedded
->GetRoot();
389 ASSERT_TRUE(WaitForTreeSizeToMatch(root_in_embedded
, 3u));
390 view11
->MoveToFront();
391 ASSERT_TRUE(WaitForOrderChange(embedded
, root_in_embedded
));
393 EXPECT_EQ(root_in_embedded
->children().front(),
394 embedded
->GetViewById(view12
->id()));
395 EXPECT_EQ(root_in_embedded
->children().back(),
396 embedded
->GetViewById(view11
->id()));
400 view11
->MoveToBack();
401 ASSERT_TRUE(WaitForOrderChange(embedded
,
402 embedded
->GetViewById(view11
->id())));
404 EXPECT_EQ(root_in_embedded
->children().front(),
405 embedded
->GetViewById(view11
->id()));
406 EXPECT_EQ(root_in_embedded
->children().back(),
407 embedded
->GetViewById(view12
->id()));
413 class VisibilityChangeObserver
: public ViewObserver
{
415 explicit VisibilityChangeObserver(View
* view
) : view_(view
) {
416 view_
->AddObserver(this);
418 ~VisibilityChangeObserver() override
{ view_
->RemoveObserver(this); }
421 // Overridden from ViewObserver:
422 void OnViewVisibilityChanged(View
* view
) override
{
423 EXPECT_EQ(view
, view_
);
424 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
429 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver
);
434 TEST_F(ViewManagerTest
, Visible
) {
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 ViewManager
* 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 visible state from the first connection and verify its mirrored
448 // correctly to the embedded app.
450 VisibilityChangeObserver
observer(embedded_root
);
451 view1
->SetVisible(false);
452 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
455 EXPECT_FALSE(view1
->visible());
456 EXPECT_FALSE(view1
->IsDrawn());
458 EXPECT_FALSE(embedded_root
->visible());
459 EXPECT_FALSE(embedded_root
->IsDrawn());
461 // Make the node visible again.
463 VisibilityChangeObserver
observer(embedded_root
);
464 view1
->SetVisible(true);
465 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
468 EXPECT_TRUE(view1
->visible());
469 EXPECT_TRUE(view1
->IsDrawn());
471 EXPECT_TRUE(embedded_root
->visible());
472 EXPECT_TRUE(embedded_root
->IsDrawn());
477 class DrawnChangeObserver
: public ViewObserver
{
479 explicit DrawnChangeObserver(View
* view
) : view_(view
) {
480 view_
->AddObserver(this);
482 ~DrawnChangeObserver() override
{ view_
->RemoveObserver(this); }
485 // Overridden from ViewObserver:
486 void OnViewDrawnChanged(View
* view
) override
{
487 EXPECT_EQ(view
, view_
);
488 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
493 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver
);
498 TEST_F(ViewManagerTest
, Drawn
) {
499 View
* view1
= window_manager()->CreateView();
500 view1
->SetVisible(true);
501 window_manager()->GetRoot()->AddChild(view1
);
503 // Embed another app and verify initial state.
504 ViewManager
* embedded
= Embed(view1
);
505 ASSERT_NE(nullptr, embedded
);
506 ASSERT_NE(nullptr, embedded
->GetRoot());
507 View
* embedded_root
= embedded
->GetRoot();
508 EXPECT_TRUE(embedded_root
->visible());
509 EXPECT_TRUE(embedded_root
->IsDrawn());
511 // Change the visibility of the root, this should propagate a drawn state
512 // change to |embedded|.
514 DrawnChangeObserver
observer(embedded_root
);
515 window_manager()->GetRoot()->SetVisible(false);
516 ASSERT_TRUE(DoRunLoopWithTimeout());
519 EXPECT_TRUE(view1
->visible());
520 EXPECT_FALSE(view1
->IsDrawn());
522 EXPECT_TRUE(embedded_root
->visible());
523 EXPECT_FALSE(embedded_root
->IsDrawn());
526 // TODO(beng): tests for view event dispatcher.
527 // - verify that we see events for all views.
531 class FocusChangeObserver
: public ViewObserver
{
533 explicit FocusChangeObserver(View
* view
)
534 : view_(view
), last_gained_focus_(nullptr), last_lost_focus_(nullptr) {
535 view_
->AddObserver(this);
537 ~FocusChangeObserver() override
{ view_
->RemoveObserver(this); }
539 View
* last_gained_focus() { return last_gained_focus_
; }
541 View
* last_lost_focus() { return last_lost_focus_
; }
544 // Overridden from ViewObserver.
545 void OnViewFocusChanged(View
* gained_focus
, View
* lost_focus
) override
{
546 last_gained_focus_
= gained_focus
;
547 last_lost_focus_
= lost_focus
;
548 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
552 View
* last_gained_focus_
;
553 View
* last_lost_focus_
;
555 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver
);
560 TEST_F(ViewManagerTest
, Focus
) {
561 View
* view1
= window_manager()->CreateView();
562 view1
->SetVisible(true);
563 window_manager()->GetRoot()->AddChild(view1
);
565 ViewManager
* embedded
= Embed(view1
);
566 ASSERT_NE(nullptr, embedded
);
567 View
* view11
= embedded
->CreateView();
568 view11
->SetVisible(true);
569 embedded
->GetRoot()->AddChild(view11
);
571 // TODO(alhaad): Figure out why switching focus between views from different
572 // connections is causing the tests to crash and add tests for that.
574 View
* embedded_root
= embedded
->GetRoot();
575 FocusChangeObserver
observer(embedded_root
);
576 embedded_root
->SetFocus();
577 ASSERT_TRUE(DoRunLoopWithTimeout());
578 ASSERT_NE(nullptr, observer
.last_gained_focus());
579 EXPECT_EQ(embedded_root
->id(), observer
.last_gained_focus()->id());
582 FocusChangeObserver
observer(view11
);
584 ASSERT_TRUE(DoRunLoopWithTimeout());
585 ASSERT_NE(nullptr, observer
.last_gained_focus());
586 ASSERT_NE(nullptr, observer
.last_lost_focus());
587 EXPECT_EQ(view11
->id(), observer
.last_gained_focus()->id());
588 EXPECT_EQ(embedded
->GetRoot()->id(), observer
.last_lost_focus()->id());
594 class DestroyedChangedObserver
: public ViewObserver
{
596 DestroyedChangedObserver(ViewManagerTestBase
* test
,
599 : test_(test
), view_(view
), got_destroy_(got_destroy
) {
600 view_
->AddObserver(this);
602 ~DestroyedChangedObserver() override
{
604 view_
->RemoveObserver(this);
608 // Overridden from ViewObserver:
609 void OnViewDestroyed(View
* view
) override
{
610 EXPECT_EQ(view
, view_
);
611 view_
->RemoveObserver(this);
612 *got_destroy_
= true;
615 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
616 EXPECT_FALSE(test_
->view_manager_destroyed());
619 ViewManagerTestBase
* test_
;
623 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver
);
628 // Verifies deleting a ViewManager sends the right notifications.
629 TEST_F(ViewManagerTest
, DeleteViewManager
) {
630 View
* view
= window_manager()->CreateView();
631 ASSERT_NE(nullptr, view
);
632 view
->SetVisible(true);
633 window_manager()->GetRoot()->AddChild(view
);
634 ViewManager
* view_manager
= Embed(view
);
635 ASSERT_TRUE(view_manager
);
636 bool got_destroy
= false;
637 DestroyedChangedObserver
observer(this, view_manager
->GetRoot(),
640 EXPECT_TRUE(view_manager_destroyed());
641 EXPECT_TRUE(got_destroy
);
644 // Verifies two Embed()s in the same view trigger deletion of the first
646 TEST_F(ViewManagerTest
, DisconnectTriggersDelete
) {
647 View
* view
= window_manager()->CreateView();
648 ASSERT_NE(nullptr, view
);
649 view
->SetVisible(true);
650 window_manager()->GetRoot()->AddChild(view
);
651 ViewManager
* view_manager
= Embed(view
);
652 EXPECT_NE(view_manager
, window_manager());
653 View
* embedded_view
= view_manager
->CreateView();
654 // Embed again, this should trigger disconnect and deletion of view_manager.
656 DestroyedChangedObserver
observer(this, embedded_view
, &got_destroy
);
657 EXPECT_FALSE(view_manager_destroyed());
659 EXPECT_TRUE(view_manager_destroyed());
662 class ViewRemovedFromParentObserver
: public ViewObserver
{
664 explicit ViewRemovedFromParentObserver(View
* view
)
665 : view_(view
), was_removed_(false) {
666 view_
->AddObserver(this);
668 ~ViewRemovedFromParentObserver() override
{ view_
->RemoveObserver(this); }
670 bool was_removed() const { return was_removed_
; }
673 // Overridden from ViewObserver:
674 void OnTreeChanged(const TreeChangeParams
& params
) override
{
675 if (params
.target
== view_
&& !params
.new_parent
)
682 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewRemovedFromParentObserver
);
685 TEST_F(ViewManagerTest
, EmbedRemovesChildren
) {
686 View
* view1
= window_manager()->CreateView();
687 View
* view2
= window_manager()->CreateView();
688 window_manager()->GetRoot()->AddChild(view1
);
689 view1
->AddChild(view2
);
691 ViewRemovedFromParentObserver
observer(view2
);
692 ConnectToApplicationAndEmbed(view1
);
693 EXPECT_TRUE(observer
.was_removed());
694 EXPECT_EQ(nullptr, view2
->parent());
695 EXPECT_TRUE(view1
->children().empty());
697 // Run the message loop so the Embed() call above completes. Without this
698 // we may end up reconnecting to the test and rerunning the test, which is
699 // problematic since the other services don't shut down.
700 ASSERT_TRUE(DoRunLoopWithTimeout());
703 TEST_F(ViewManagerTest
, OnWillEmbed
) {
704 window_manager()->SetEmbedRoot();
706 View
* view1
= window_manager()->CreateView();
707 window_manager()->GetRoot()->AddChild(view1
);
709 ViewManager
* view_manager
= EmbedAllowingReembed(view1
);
710 View
* view2
= view_manager
->CreateView();
711 view_manager
->GetRoot()->AddChild(view2
);
713 EmbedAllowingReembed(view2
);
714 EXPECT_EQ(1u, on_will_embed_count());
717 // Verifies Embed() doesn't succeed if OnWillEmbed() returns false.
718 TEST_F(ViewManagerTest
, OnWillEmbedFails
) {
719 window_manager()->SetEmbedRoot();
721 View
* view1
= window_manager()->CreateView();
722 window_manager()->GetRoot()->AddChild(view1
);
724 ViewManager
* view_manager
= Embed(view1
);
725 View
* view2
= view_manager
->CreateView();
726 view_manager
->GetRoot()->AddChild(view2
);
728 clear_on_will_embed_count();
729 set_on_will_embed_return_value(false);
730 mojo::URLRequestPtr
request(mojo::URLRequest::New());
731 request
->url
= application_impl()->url();
732 view2
->EmbedAllowingReembed(request
.Pass());
734 EXPECT_TRUE(DoRunLoopWithTimeout());
735 EXPECT_EQ(1u, on_will_embed_count());
737 // The run loop above quits when OnWillEmbed() returns, which means it's
738 // possible there is still an OnEmbed() message in flight. Sets the bounds of
739 // |view1| and wait for it to the change in |view_manager|, that way we know
740 // |view_manager| has processed all messages for it.
741 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
743 EXPECT_EQ(1u, on_will_embed_count());
746 // Verify an Embed() from an ancestor is not allowed.
747 TEST_F(ViewManagerTest
, ReembedFails
) {
748 window_manager()->SetEmbedRoot();
750 View
* view1
= window_manager()->CreateView();
751 window_manager()->GetRoot()->AddChild(view1
);
753 ViewManager
* view_manager
= Embed(view1
);
754 ASSERT_TRUE(view_manager
);
755 View
* view2
= view_manager
->CreateView();
756 view_manager
->GetRoot()->AddChild(view2
);
759 // Try to embed in view2 from the window_manager. This should fail as the
760 // Embed() didn't grab reembed.
761 View
* view2_in_wm
= window_manager()->GetViewById(view2
->id());
762 ConnectToApplicationAndEmbed(view2_in_wm
);
764 // The Embed() call above returns immediately. To ensure the server has
765 // processed it nudge the bounds and wait for it to be processed.
766 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
768 EXPECT_EQ(nullptr, most_recent_view_manager());
771 // Verify an Embed() from an ancestor is allowed if the ancestor is an embed
772 // root and Embed was done by way of EmbedAllowingReembed().
773 TEST_F(ViewManagerTest
, ReembedSucceeds
) {
774 window_manager()->SetEmbedRoot();
776 View
* view1
= window_manager()->CreateView();
777 window_manager()->GetRoot()->AddChild(view1
);
779 ViewManager
* view_manager
= Embed(view1
);
780 View
* view2
= view_manager
->CreateView();
781 view_manager
->GetRoot()->AddChild(view2
);
782 EmbedAllowingReembed(view2
);
784 View
* view2_in_wm
= window_manager()->GetViewById(view2
->id());
785 ViewManager
* view_manager2
= Embed(view2_in_wm
);
786 ASSERT_TRUE(view_manager2
);
788 // The Embed() call above returns immediately. To ensure the server has
789 // processed it nudge the bounds and wait for it to be processed.
790 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
792 EXPECT_EQ(nullptr, most_recent_view_manager());
797 class DestroyObserver
: public ViewObserver
{
799 DestroyObserver(ViewManagerTestBase
* test
, ViewManager
* vm
, bool* got_destroy
)
800 : test_(test
), got_destroy_(got_destroy
) {
801 vm
->GetRoot()->AddObserver(this);
803 ~DestroyObserver() override
{}
806 // Overridden from ViewObserver:
807 void OnViewDestroyed(View
* view
) override
{
808 *got_destroy_
= true;
809 view
->RemoveObserver(this);
811 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
812 EXPECT_FALSE(test_
->view_manager_destroyed());
814 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
817 ViewManagerTestBase
* test_
;
820 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyObserver
);
825 // Verifies deleting a View that is the root of another connection notifies
826 // observers in the right order (OnViewDestroyed() before
827 // OnViewManagerDestroyed()).
828 TEST_F(ViewManagerTest
, ViewManagerDestroyedAfterRootObserver
) {
829 View
* embed_view
= window_manager()->CreateView();
830 window_manager()->GetRoot()->AddChild(embed_view
);
832 ViewManager
* embedded_view_manager
= Embed(embed_view
);
834 bool got_destroy
= false;
835 DestroyObserver
observer(this, embedded_view_manager
, &got_destroy
);
836 // Delete the view |embedded_view_manager| is embedded in. This is async,
837 // but will eventually trigger deleting |embedded_view_manager|.
838 embed_view
->Destroy();
839 EXPECT_TRUE(DoRunLoopWithTimeout());
840 EXPECT_TRUE(got_destroy
);
843 // Verifies an embed root sees views created beneath it from another
845 TEST_F(ViewManagerTest
, EmbedRootSeesHierarchyChanged
) {
846 View
* embed_view
= window_manager()->CreateView();
847 window_manager()->GetRoot()->AddChild(embed_view
);
849 ViewManager
* vm2
= Embed(embed_view
);
851 View
* vm2_v1
= vm2
->CreateView();
852 vm2
->GetRoot()->AddChild(vm2_v1
);
854 ViewManager
* vm3
= Embed(vm2_v1
);
855 View
* vm3_v1
= vm3
->CreateView();
856 vm3
->GetRoot()->AddChild(vm3_v1
);
858 // As |vm2| is an embed root it should get notified about |vm3_v1|.
859 ASSERT_TRUE(WaitForTreeSizeToMatch(vm2_v1
, 2));
862 TEST_F(ViewManagerTest
, EmbedFromEmbedRoot
) {
863 View
* embed_view
= window_manager()->CreateView();
864 window_manager()->GetRoot()->AddChild(embed_view
);
866 ViewManager
* vm2
= Embed(embed_view
);
868 View
* vm2_v1
= vm2
->CreateView();
869 vm2
->GetRoot()->AddChild(vm2_v1
);
871 ViewManager
* vm3
= Embed(vm2_v1
);
872 View
* vm3_v1
= vm3
->CreateView();
873 vm3
->GetRoot()->AddChild(vm3_v1
);
875 // As |vm2| is an embed root it should get notified about |vm3_v1|.
876 ASSERT_TRUE(WaitForTreeSizeToMatch(vm2_v1
, 2));
878 // Embed() from vm2 in vm3_v1. This is allowed as vm2 is an embed root.
879 ASSERT_EQ(1u, vm2_v1
->children().size());
880 View
* vm3_v1_in_vm2
= vm2_v1
->children()[0];
881 ASSERT_TRUE(Embed(vm3_v1_in_vm2
));