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"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/test/test_timeouts.h"
14 #include "components/view_manager/public/cpp/lib/view_manager_client_impl.h"
15 #include "components/view_manager/public/cpp/tests/view_manager_test_base.h"
16 #include "components/view_manager/public/cpp/view_manager_client_factory.h"
17 #include "components/view_manager/public/cpp/view_manager_delegate.h"
18 #include "components/view_manager/public/cpp/view_manager_init.h"
19 #include "components/view_manager/public/cpp/view_observer.h"
20 #include "mojo/application/public/cpp/application_connection.h"
21 #include "mojo/application/public/cpp/application_delegate.h"
22 #include "mojo/application/public/cpp/application_impl.h"
23 #include "mojo/application/public/cpp/application_test_base.h"
24 #include "mojo/application/public/cpp/service_provider_impl.h"
25 #include "ui/mojo/geometry/geometry_util.h"
31 class BoundsChangeObserver
: public ViewObserver
{
33 explicit BoundsChangeObserver(View
* view
) : view_(view
) {
34 view_
->AddObserver(this);
36 ~BoundsChangeObserver() override
{ view_
->RemoveObserver(this); }
39 // Overridden from ViewObserver:
40 void OnViewBoundsChanged(View
* view
,
41 const Rect
& old_bounds
,
42 const Rect
& new_bounds
) override
{
43 DCHECK_EQ(view
, view_
);
44 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
49 MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver
);
52 // Wait until the bounds of the supplied view change; returns false on timeout.
53 bool WaitForBoundsToChange(View
* view
) {
54 BoundsChangeObserver
observer(view
);
55 return ViewManagerTestBase::DoRunLoopWithTimeout();
58 // Increments the width of |view| and waits for a bounds change in |other_vm|s
60 bool IncrementWidthAndWaitForChange(View
* view
, ViewManager
* other_vm
) {
61 mojo::Rect bounds
= view
->bounds();
63 view
->SetBounds(bounds
);
64 View
* view_in_vm
= other_vm
->GetRoot();
65 if (view_in_vm
== view
|| view_in_vm
->id() != view
->id())
67 return WaitForBoundsToChange(view_in_vm
);
70 // Spins a run loop until the tree beginning at |root| has |tree_size| views
71 // (including |root|).
72 class TreeSizeMatchesObserver
: public ViewObserver
{
74 TreeSizeMatchesObserver(View
* tree
, size_t tree_size
)
75 : tree_(tree
), tree_size_(tree_size
) {
76 tree_
->AddObserver(this);
78 ~TreeSizeMatchesObserver() override
{ tree_
->RemoveObserver(this); }
80 bool IsTreeCorrectSize() { return CountViews(tree_
) == tree_size_
; }
83 // Overridden from ViewObserver:
84 void OnTreeChanged(const TreeChangeParams
& params
) override
{
85 if (IsTreeCorrectSize())
86 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
89 size_t CountViews(const View
* view
) const {
91 View::Children::const_iterator it
= view
->children().begin();
92 for (; it
!= view
->children().end(); ++it
)
93 count
+= CountViews(*it
);
100 MOJO_DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver
);
103 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
104 bool WaitForTreeSizeToMatch(View
* view
, size_t tree_size
) {
105 TreeSizeMatchesObserver
observer(view
, tree_size
);
106 return observer
.IsTreeCorrectSize() ||
107 ViewManagerTestBase::DoRunLoopWithTimeout();
110 class OrderChangeObserver
: public ViewObserver
{
112 OrderChangeObserver(View
* view
) : view_(view
) { view_
->AddObserver(this); }
113 ~OrderChangeObserver() override
{ view_
->RemoveObserver(this); }
116 // Overridden from ViewObserver:
117 void OnViewReordered(View
* view
,
119 OrderDirection direction
) override
{
120 DCHECK_EQ(view
, view_
);
121 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
126 MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver
);
129 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
130 bool WaitForOrderChange(ViewManager
* view_manager
, View
* view
) {
131 OrderChangeObserver
observer(view
);
132 return ViewManagerTestBase::DoRunLoopWithTimeout();
135 // Tracks a view's destruction. Query is_valid() for current state.
136 class ViewTracker
: public ViewObserver
{
138 explicit ViewTracker(View
* view
) : view_(view
) { view_
->AddObserver(this); }
139 ~ViewTracker() override
{
141 view_
->RemoveObserver(this);
144 bool is_valid() const { return !!view_
; }
147 // Overridden from ViewObserver:
148 void OnViewDestroyed(View
* view
) override
{
149 DCHECK_EQ(view
, view_
);
156 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker
);
161 // ViewManager -----------------------------------------------------------------
163 // These tests model synchronization of two peer connections to the view manager
164 // service, that are given access to some root view.
166 class ViewManagerTest
: public ViewManagerTestBase
{
169 : on_will_embed_count_(0u), on_will_embed_return_value_(true) {}
171 void clear_on_will_embed_count() { on_will_embed_count_
= 0u; }
172 size_t on_will_embed_count() const { return on_will_embed_count_
; }
174 void set_on_will_embed_return_value(bool value
) {
175 on_will_embed_return_value_
= value
;
178 // Embeds another version of the test app @ view. This runs a run loop until
179 // a response is received, or a timeout. On success the new ViewManager is
181 ViewManager
* Embed(View
* view
) {
182 return EmbedImpl(view
, EmbedType::NO_REEMBED
);
185 // Same as Embed(), but uses EmbedAllowingReembed().
186 ViewManager
* EmbedAllowingReembed(View
* view
) {
187 return EmbedImpl(view
, EmbedType::ALLOW_REEMBED
);
190 // Establishes a connection to this application and asks for a
191 // ViewManagerClient. The ViewManagerClient is then embedded in |view|.
192 // This does *not* wait for the connection to complete.
193 void ConnectToApplicationAndEmbed(View
* view
) {
194 mojo::URLRequestPtr
request(mojo::URLRequest::New());
195 request
->url
= mojo::String::From(application_impl()->url());
196 ApplicationConnection
* connection
=
197 application_impl()->ConnectToApplication(request
.Pass());
198 mojo::ViewManagerClientPtr client
;
199 connection
->ConnectToService(&client
);
200 view
->Embed(client
.Pass());
203 // Overridden from ViewManagerDelegate:
204 void OnEmbedForDescendant(View
* view
,
205 mojo::URLRequestPtr request
,
206 mojo::ViewManagerClientPtr
* client
) override
{
207 on_will_embed_count_
++;
208 if (on_will_embed_return_value_
) {
209 ApplicationConnection
* connection
=
210 application_impl()->ConnectToApplication(request
.Pass());
211 connection
->ConnectToService(client
);
213 EXPECT_TRUE(QuitRunLoop());
218 enum class EmbedType
{
223 ViewManager
* EmbedImpl(View
* view
, EmbedType type
) {
224 most_recent_view_manager_
= nullptr;
225 if (type
== EmbedType::ALLOW_REEMBED
) {
226 mojo::URLRequestPtr
request(mojo::URLRequest::New());
227 request
->url
= mojo::String::From(application_impl()->url());
228 view
->EmbedAllowingReembed(request
.Pass());
230 ConnectToApplicationAndEmbed(view
);
232 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
234 ViewManager
* vm
= nullptr;
235 std::swap(vm
, most_recent_view_manager_
);
239 // Number of times OnWillEmbed() has been called.
240 size_t on_will_embed_count_
;
242 // Value OnWillEmbed() should return.
243 bool on_will_embed_return_value_
;
245 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTest
);
248 TEST_F(ViewManagerTest
, RootView
) {
249 ASSERT_NE(nullptr, window_manager());
250 EXPECT_NE(nullptr, window_manager()->GetRoot());
253 TEST_F(ViewManagerTest
, Embed
) {
254 View
* view
= window_manager()->CreateView();
255 ASSERT_NE(nullptr, view
);
256 view
->SetVisible(true);
257 window_manager()->GetRoot()->AddChild(view
);
258 ViewManager
* embedded
= Embed(view
);
259 ASSERT_NE(nullptr, embedded
);
261 View
* view_in_embedded
= embedded
->GetRoot();
262 ASSERT_NE(nullptr, view_in_embedded
);
263 EXPECT_EQ(view
->id(), view_in_embedded
->id());
264 EXPECT_EQ(nullptr, view_in_embedded
->parent());
265 EXPECT_TRUE(view_in_embedded
->children().empty());
268 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see
270 TEST_F(ViewManagerTest
, EmbeddedDoesntSeeChild
) {
271 View
* view
= window_manager()->CreateView();
272 ASSERT_NE(nullptr, view
);
273 view
->SetVisible(true);
274 window_manager()->GetRoot()->AddChild(view
);
275 View
* nested
= window_manager()->CreateView();
276 ASSERT_NE(nullptr, nested
);
277 nested
->SetVisible(true);
278 view
->AddChild(nested
);
280 ViewManager
* embedded
= Embed(view
);
281 ASSERT_NE(nullptr, embedded
);
282 View
* view_in_embedded
= embedded
->GetRoot();
283 EXPECT_EQ(view
->id(), view_in_embedded
->id());
284 EXPECT_EQ(nullptr, view_in_embedded
->parent());
285 EXPECT_TRUE(view_in_embedded
->children().empty());
288 // TODO(beng): write a replacement test for the one that once existed here:
289 // This test validates the following scenario:
290 // - a view originating from one connection
291 // - a view originating from a second connection
292 // + the connection originating the view is destroyed
293 // -> the view should still exist (since the second connection is live) but
294 // should be disconnected from any views.
295 // http://crbug.com/396300
297 // TODO(beng): The new test should validate the scenario as described above
298 // except that the second connection still has a valid tree.
300 // Verifies that bounds changes applied to a view hierarchy in one connection
301 // are reflected to another.
302 TEST_F(ViewManagerTest
, SetBounds
) {
303 View
* view
= window_manager()->CreateView();
304 view
->SetVisible(true);
305 window_manager()->GetRoot()->AddChild(view
);
306 ViewManager
* embedded
= Embed(view
);
307 ASSERT_NE(nullptr, embedded
);
309 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
310 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
313 rect
.width
= rect
.height
= 100;
314 view
->SetBounds(rect
);
315 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
316 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
319 // Verifies that bounds changes applied to a view owned by a different
320 // connection are refused.
321 TEST_F(ViewManagerTest
, SetBoundsSecurity
) {
322 View
* view
= window_manager()->CreateView();
323 view
->SetVisible(true);
324 window_manager()->GetRoot()->AddChild(view
);
325 ViewManager
* embedded
= Embed(view
);
326 ASSERT_NE(nullptr, embedded
);
328 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
332 view
->SetBounds(rect
);
333 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded
));
337 view_in_embedded
->SetBounds(rect
);
338 // Bounds change should have been rejected.
339 EXPECT_EQ(view
->bounds(), view_in_embedded
->bounds());
342 // Verifies that a view can only be destroyed by the connection that created it.
343 TEST_F(ViewManagerTest
, DestroySecurity
) {
344 View
* view
= window_manager()->CreateView();
345 view
->SetVisible(true);
346 window_manager()->GetRoot()->AddChild(view
);
347 ViewManager
* embedded
= Embed(view
);
348 ASSERT_NE(nullptr, embedded
);
350 View
* view_in_embedded
= embedded
->GetViewById(view
->id());
352 ViewTracker
tracker2(view_in_embedded
);
353 view_in_embedded
->Destroy();
354 // View should not have been destroyed.
355 EXPECT_TRUE(tracker2
.is_valid());
357 ViewTracker
tracker1(view
);
359 EXPECT_FALSE(tracker1
.is_valid());
362 TEST_F(ViewManagerTest
, MultiRoots
) {
363 View
* view1
= window_manager()->CreateView();
364 view1
->SetVisible(true);
365 window_manager()->GetRoot()->AddChild(view1
);
366 View
* view2
= window_manager()->CreateView();
367 view2
->SetVisible(true);
368 window_manager()->GetRoot()->AddChild(view2
);
369 ViewManager
* embedded1
= Embed(view1
);
370 ASSERT_NE(nullptr, embedded1
);
371 ViewManager
* embedded2
= Embed(view2
);
372 ASSERT_NE(nullptr, embedded2
);
373 EXPECT_NE(embedded1
, embedded2
);
376 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
377 // Debug and re-enable this.
378 TEST_F(ViewManagerTest
, DISABLED_Reorder
) {
379 View
* view1
= window_manager()->CreateView();
380 view1
->SetVisible(true);
381 window_manager()->GetRoot()->AddChild(view1
);
383 ViewManager
* embedded
= Embed(view1
);
384 ASSERT_NE(nullptr, embedded
);
386 View
* view11
= embedded
->CreateView();
387 view11
->SetVisible(true);
388 embedded
->GetRoot()->AddChild(view11
);
389 View
* view12
= embedded
->CreateView();
390 view12
->SetVisible(true);
391 embedded
->GetRoot()->AddChild(view12
);
393 View
* root_in_embedded
= embedded
->GetRoot();
396 ASSERT_TRUE(WaitForTreeSizeToMatch(root_in_embedded
, 3u));
397 view11
->MoveToFront();
398 ASSERT_TRUE(WaitForOrderChange(embedded
, root_in_embedded
));
400 EXPECT_EQ(root_in_embedded
->children().front(),
401 embedded
->GetViewById(view12
->id()));
402 EXPECT_EQ(root_in_embedded
->children().back(),
403 embedded
->GetViewById(view11
->id()));
407 view11
->MoveToBack();
408 ASSERT_TRUE(WaitForOrderChange(embedded
,
409 embedded
->GetViewById(view11
->id())));
411 EXPECT_EQ(root_in_embedded
->children().front(),
412 embedded
->GetViewById(view11
->id()));
413 EXPECT_EQ(root_in_embedded
->children().back(),
414 embedded
->GetViewById(view12
->id()));
420 class VisibilityChangeObserver
: public ViewObserver
{
422 explicit VisibilityChangeObserver(View
* view
) : view_(view
) {
423 view_
->AddObserver(this);
425 ~VisibilityChangeObserver() override
{ view_
->RemoveObserver(this); }
428 // Overridden from ViewObserver:
429 void OnViewVisibilityChanged(View
* view
) override
{
430 EXPECT_EQ(view
, view_
);
431 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
436 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver
);
441 TEST_F(ViewManagerTest
, Visible
) {
442 View
* view1
= window_manager()->CreateView();
443 view1
->SetVisible(true);
444 window_manager()->GetRoot()->AddChild(view1
);
446 // Embed another app and verify initial state.
447 ViewManager
* embedded
= Embed(view1
);
448 ASSERT_NE(nullptr, embedded
);
449 ASSERT_NE(nullptr, embedded
->GetRoot());
450 View
* embedded_root
= embedded
->GetRoot();
451 EXPECT_TRUE(embedded_root
->visible());
452 EXPECT_TRUE(embedded_root
->IsDrawn());
454 // Change the visible state from the first connection and verify its mirrored
455 // correctly to the embedded app.
457 VisibilityChangeObserver
observer(embedded_root
);
458 view1
->SetVisible(false);
459 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
462 EXPECT_FALSE(view1
->visible());
463 EXPECT_FALSE(view1
->IsDrawn());
465 EXPECT_FALSE(embedded_root
->visible());
466 EXPECT_FALSE(embedded_root
->IsDrawn());
468 // Make the node visible again.
470 VisibilityChangeObserver
observer(embedded_root
);
471 view1
->SetVisible(true);
472 ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
475 EXPECT_TRUE(view1
->visible());
476 EXPECT_TRUE(view1
->IsDrawn());
478 EXPECT_TRUE(embedded_root
->visible());
479 EXPECT_TRUE(embedded_root
->IsDrawn());
484 class DrawnChangeObserver
: public ViewObserver
{
486 explicit DrawnChangeObserver(View
* view
) : view_(view
) {
487 view_
->AddObserver(this);
489 ~DrawnChangeObserver() override
{ view_
->RemoveObserver(this); }
492 // Overridden from ViewObserver:
493 void OnViewDrawnChanged(View
* view
) override
{
494 EXPECT_EQ(view
, view_
);
495 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
500 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver
);
505 TEST_F(ViewManagerTest
, Drawn
) {
506 View
* view1
= window_manager()->CreateView();
507 view1
->SetVisible(true);
508 window_manager()->GetRoot()->AddChild(view1
);
510 // Embed another app and verify initial state.
511 ViewManager
* embedded
= Embed(view1
);
512 ASSERT_NE(nullptr, embedded
);
513 ASSERT_NE(nullptr, embedded
->GetRoot());
514 View
* embedded_root
= embedded
->GetRoot();
515 EXPECT_TRUE(embedded_root
->visible());
516 EXPECT_TRUE(embedded_root
->IsDrawn());
518 // Change the visibility of the root, this should propagate a drawn state
519 // change to |embedded|.
521 DrawnChangeObserver
observer(embedded_root
);
522 window_manager()->GetRoot()->SetVisible(false);
523 ASSERT_TRUE(DoRunLoopWithTimeout());
526 EXPECT_TRUE(view1
->visible());
527 EXPECT_FALSE(view1
->IsDrawn());
529 EXPECT_TRUE(embedded_root
->visible());
530 EXPECT_FALSE(embedded_root
->IsDrawn());
533 // TODO(beng): tests for view event dispatcher.
534 // - verify that we see events for all views.
538 class FocusChangeObserver
: public ViewObserver
{
540 explicit FocusChangeObserver(View
* view
)
541 : view_(view
), last_gained_focus_(nullptr), last_lost_focus_(nullptr) {
542 view_
->AddObserver(this);
544 ~FocusChangeObserver() override
{ view_
->RemoveObserver(this); }
546 View
* last_gained_focus() { return last_gained_focus_
; }
548 View
* last_lost_focus() { return last_lost_focus_
; }
551 // Overridden from ViewObserver.
552 void OnViewFocusChanged(View
* gained_focus
, View
* lost_focus
) override
{
553 last_gained_focus_
= gained_focus
;
554 last_lost_focus_
= lost_focus
;
555 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
559 View
* last_gained_focus_
;
560 View
* last_lost_focus_
;
562 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver
);
567 TEST_F(ViewManagerTest
, Focus
) {
568 View
* view1
= window_manager()->CreateView();
569 view1
->SetVisible(true);
570 window_manager()->GetRoot()->AddChild(view1
);
572 ViewManager
* embedded
= Embed(view1
);
573 ASSERT_NE(nullptr, embedded
);
574 View
* view11
= embedded
->CreateView();
575 view11
->SetVisible(true);
576 embedded
->GetRoot()->AddChild(view11
);
578 // TODO(alhaad): Figure out why switching focus between views from different
579 // connections is causing the tests to crash and add tests for that.
581 View
* embedded_root
= embedded
->GetRoot();
582 FocusChangeObserver
observer(embedded_root
);
583 embedded_root
->SetFocus();
584 ASSERT_TRUE(DoRunLoopWithTimeout());
585 ASSERT_NE(nullptr, observer
.last_gained_focus());
586 EXPECT_EQ(embedded_root
->id(), observer
.last_gained_focus()->id());
589 FocusChangeObserver
observer(view11
);
591 ASSERT_TRUE(DoRunLoopWithTimeout());
592 ASSERT_NE(nullptr, observer
.last_gained_focus());
593 ASSERT_NE(nullptr, observer
.last_lost_focus());
594 EXPECT_EQ(view11
->id(), observer
.last_gained_focus()->id());
595 EXPECT_EQ(embedded
->GetRoot()->id(), observer
.last_lost_focus()->id());
601 class DestroyedChangedObserver
: public ViewObserver
{
603 DestroyedChangedObserver(View
* view
, bool* got_destroy
)
605 got_destroy_(got_destroy
) {
606 view_
->AddObserver(this);
608 ~DestroyedChangedObserver() override
{
610 view_
->RemoveObserver(this);
614 // Overridden from ViewObserver:
615 void OnViewDestroyed(View
* view
) override
{
616 EXPECT_EQ(view
, view_
);
617 view_
->RemoveObserver(this);
618 *got_destroy_
= true;
625 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver
);
630 // Verifies deleting a ViewManager sends the right notifications.
631 TEST_F(ViewManagerTest
, DeleteViewManager
) {
632 View
* view
= window_manager()->CreateView();
633 ASSERT_NE(nullptr, view
);
634 view
->SetVisible(true);
635 window_manager()->GetRoot()->AddChild(view
);
636 ViewManager
* view_manager
= Embed(view
);
637 ASSERT_TRUE(view_manager
);
638 bool got_destroy
= false;
639 DestroyedChangedObserver
observer(view_manager
->GetRoot(), &got_destroy
);
641 EXPECT_TRUE(view_manager_destroyed());
642 EXPECT_TRUE(got_destroy
);
645 // Verifies two Embed()s in the same view trigger deletion of the first
647 TEST_F(ViewManagerTest
, DisconnectTriggersDelete
) {
648 View
* view
= window_manager()->CreateView();
649 ASSERT_NE(nullptr, view
);
650 view
->SetVisible(true);
651 window_manager()->GetRoot()->AddChild(view
);
652 ViewManager
* view_manager
= Embed(view
);
653 EXPECT_NE(view_manager
, window_manager());
654 View
* embedded_view
= view_manager
->CreateView();
655 // Embed again, this should trigger disconnect and deletion of view_manager.
657 DestroyedChangedObserver
observer(embedded_view
, &got_destroy
);
658 EXPECT_FALSE(view_manager_destroyed());
660 EXPECT_TRUE(view_manager_destroyed());
663 class ViewRemovedFromParentObserver
: public ViewObserver
{
665 explicit ViewRemovedFromParentObserver(View
* view
)
666 : view_(view
), was_removed_(false) {
667 view_
->AddObserver(this);
669 ~ViewRemovedFromParentObserver() override
{ view_
->RemoveObserver(this); }
671 bool was_removed() const { return was_removed_
; }
674 // Overridden from ViewObserver:
675 void OnTreeChanged(const TreeChangeParams
& params
) override
{
676 if (params
.target
== view_
&& !params
.new_parent
)
683 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewRemovedFromParentObserver
);
686 TEST_F(ViewManagerTest
, EmbedRemovesChildren
) {
687 View
* view1
= window_manager()->CreateView();
688 View
* view2
= window_manager()->CreateView();
689 window_manager()->GetRoot()->AddChild(view1
);
690 view1
->AddChild(view2
);
692 ViewRemovedFromParentObserver
observer(view2
);
693 ConnectToApplicationAndEmbed(view1
);
694 EXPECT_TRUE(observer
.was_removed());
695 EXPECT_EQ(nullptr, view2
->parent());
696 EXPECT_TRUE(view1
->children().empty());
698 // Run the message loop so the Embed() call above completes. Without this
699 // we may end up reconnecting to the test and rerunning the test, which is
700 // problematic since the other services don't shut down.
701 ASSERT_TRUE(DoRunLoopWithTimeout());
704 TEST_F(ViewManagerTest
, OnWillEmbed
) {
705 window_manager()->SetEmbedRoot();
707 View
* view1
= window_manager()->CreateView();
708 window_manager()->GetRoot()->AddChild(view1
);
710 ViewManager
* view_manager
= EmbedAllowingReembed(view1
);
711 View
* view2
= view_manager
->CreateView();
712 view_manager
->GetRoot()->AddChild(view2
);
714 EmbedAllowingReembed(view2
);
715 EXPECT_EQ(1u, on_will_embed_count());
718 // Verifies Embed() doesn't succeed if OnWillEmbed() returns false.
719 TEST_F(ViewManagerTest
, OnWillEmbedFails
) {
720 window_manager()->SetEmbedRoot();
722 View
* view1
= window_manager()->CreateView();
723 window_manager()->GetRoot()->AddChild(view1
);
725 ViewManager
* view_manager
= Embed(view1
);
726 View
* view2
= view_manager
->CreateView();
727 view_manager
->GetRoot()->AddChild(view2
);
729 clear_on_will_embed_count();
730 set_on_will_embed_return_value(false);
731 mojo::URLRequestPtr
request(mojo::URLRequest::New());
732 request
->url
= application_impl()->url();
733 view2
->EmbedAllowingReembed(request
.Pass());
735 EXPECT_TRUE(DoRunLoopWithTimeout());
736 EXPECT_EQ(1u, on_will_embed_count());
738 // The run loop above quits when OnWillEmbed() returns, which means it's
739 // possible there is still an OnEmbed() message in flight. Sets the bounds of
740 // |view1| and wait for it to the change in |view_manager|, that way we know
741 // |view_manager| has processed all messages for it.
742 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
744 EXPECT_EQ(1u, on_will_embed_count());
747 // Verify an Embed() from an ancestor is not allowed.
748 TEST_F(ViewManagerTest
, ReembedFails
) {
749 window_manager()->SetEmbedRoot();
751 View
* view1
= window_manager()->CreateView();
752 window_manager()->GetRoot()->AddChild(view1
);
754 ViewManager
* view_manager
= Embed(view1
);
755 ASSERT_TRUE(view_manager
);
756 View
* view2
= view_manager
->CreateView();
757 view_manager
->GetRoot()->AddChild(view2
);
760 // Try to embed in view2 from the window_manager. This should fail as the
761 // Embed() didn't grab reembed.
762 View
* view2_in_wm
= window_manager()->GetViewById(view2
->id());
763 ConnectToApplicationAndEmbed(view2_in_wm
);
765 // The Embed() call above returns immediately. To ensure the server has
766 // processed it nudge the bounds and wait for it to be processed.
767 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
769 EXPECT_EQ(nullptr, most_recent_view_manager());
772 // Verify an Embed() from an ancestor is allowed if the ancestor is an embed
773 // root and Embed was done by way of EmbedAllowingReembed().
774 TEST_F(ViewManagerTest
, ReembedSucceeds
) {
775 window_manager()->SetEmbedRoot();
777 View
* view1
= window_manager()->CreateView();
778 window_manager()->GetRoot()->AddChild(view1
);
780 ViewManager
* view_manager
= Embed(view1
);
781 View
* view2
= view_manager
->CreateView();
782 view_manager
->GetRoot()->AddChild(view2
);
783 EmbedAllowingReembed(view2
);
785 View
* view2_in_wm
= window_manager()->GetViewById(view2
->id());
786 ViewManager
* view_manager2
= Embed(view2_in_wm
);
787 ASSERT_TRUE(view_manager2
);
789 // The Embed() call above returns immediately. To ensure the server has
790 // processed it nudge the bounds and wait for it to be processed.
791 EXPECT_TRUE(IncrementWidthAndWaitForChange(view1
, view_manager
));
793 EXPECT_EQ(nullptr, most_recent_view_manager());