[Media Router] Add integration tests and e2e tests for media router and presentation...
[chromium-blink-merge.git] / components / view_manager / view_manager_client_apptest.cc
blobd2e750cf2fd18def950459c797c280121d1f04b0
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/bind.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"
27 namespace mojo {
29 namespace {
31 class BoundsChangeObserver : public ViewObserver {
32 public:
33 explicit BoundsChangeObserver(View* view) : view_(view) {
34 view_->AddObserver(this);
36 ~BoundsChangeObserver() override { view_->RemoveObserver(this); }
38 private:
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());
47 View* view_;
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
59 // root.
60 bool IncrementWidthAndWaitForChange(View* view, ViewManager* other_vm) {
61 mojo::Rect bounds = view->bounds();
62 bounds.width++;
63 view->SetBounds(bounds);
64 View* view_in_vm = other_vm->GetRoot();
65 if (view_in_vm == view || view_in_vm->id() != view->id())
66 return false;
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 {
73 public:
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_; }
82 private:
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 {
90 size_t count = 1;
91 View::Children::const_iterator it = view->children().begin();
92 for (; it != view->children().end(); ++it)
93 count += CountViews(*it);
94 return count;
97 View* tree_;
98 size_t tree_size_;
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 {
111 public:
112 OrderChangeObserver(View* view) : view_(view) { view_->AddObserver(this); }
113 ~OrderChangeObserver() override { view_->RemoveObserver(this); }
115 private:
116 // Overridden from ViewObserver:
117 void OnViewReordered(View* view,
118 View* relative_view,
119 OrderDirection direction) override {
120 DCHECK_EQ(view, view_);
121 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
124 View* view_;
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 {
137 public:
138 explicit ViewTracker(View* view) : view_(view) { view_->AddObserver(this); }
139 ~ViewTracker() override {
140 if (view_)
141 view_->RemoveObserver(this);
144 bool is_valid() const { return !!view_; }
146 private:
147 // Overridden from ViewObserver:
148 void OnViewDestroyed(View* view) override {
149 DCHECK_EQ(view, view_);
150 view_ = nullptr;
153 int id_;
154 View* view_;
156 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker);
159 } // namespace
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 {
167 public:
168 ViewManagerTest()
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
180 // returned.
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);
212 } else {
213 EXPECT_TRUE(QuitRunLoop());
217 private:
218 enum class EmbedType {
219 ALLOW_REEMBED,
220 NO_REEMBED,
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());
229 } else {
230 ConnectToApplicationAndEmbed(view);
232 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
233 return nullptr;
234 ViewManager* vm = nullptr;
235 std::swap(vm, most_recent_view_manager_);
236 return vm;
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
269 // N11.
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());
312 Rect rect;
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());
329 Rect rect;
330 rect.width = 800;
331 rect.height = 600;
332 view->SetBounds(rect);
333 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
335 rect.width = 1024;
336 rect.height = 768;
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);
358 view->Destroy();
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()));
418 namespace {
420 class VisibilityChangeObserver : public ViewObserver {
421 public:
422 explicit VisibilityChangeObserver(View* view) : view_(view) {
423 view_->AddObserver(this);
425 ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
427 private:
428 // Overridden from ViewObserver:
429 void OnViewVisibilityChanged(View* view) override {
430 EXPECT_EQ(view, view_);
431 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
434 View* view_;
436 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
439 } // namespace
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());
482 namespace {
484 class DrawnChangeObserver : public ViewObserver {
485 public:
486 explicit DrawnChangeObserver(View* view) : view_(view) {
487 view_->AddObserver(this);
489 ~DrawnChangeObserver() override { view_->RemoveObserver(this); }
491 private:
492 // Overridden from ViewObserver:
493 void OnViewDrawnChanged(View* view) override {
494 EXPECT_EQ(view, view_);
495 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
498 View* view_;
500 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
503 } // namespace
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.
536 namespace {
538 class FocusChangeObserver : public ViewObserver {
539 public:
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_; }
550 private:
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());
558 View* view_;
559 View* last_gained_focus_;
560 View* last_lost_focus_;
562 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
565 } // namespace
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);
590 view11->SetFocus();
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());
599 namespace {
601 class DestroyedChangedObserver : public ViewObserver {
602 public:
603 DestroyedChangedObserver(View* view, bool* got_destroy)
604 : view_(view),
605 got_destroy_(got_destroy) {
606 view_->AddObserver(this);
608 ~DestroyedChangedObserver() override {
609 if (view_)
610 view_->RemoveObserver(this);
613 private:
614 // Overridden from ViewObserver:
615 void OnViewDestroyed(View* view) override {
616 EXPECT_EQ(view, view_);
617 view_->RemoveObserver(this);
618 *got_destroy_ = true;
619 view_ = nullptr;
622 View* view_;
623 bool* got_destroy_;
625 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver);
628 } // namespace
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);
640 delete view_manager;
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
646 // ViewManager.
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.
656 bool got_destroy;
657 DestroyedChangedObserver observer(embedded_view, &got_destroy);
658 EXPECT_FALSE(view_manager_destroyed());
659 Embed(view);
660 EXPECT_TRUE(view_manager_destroyed());
663 class ViewRemovedFromParentObserver : public ViewObserver {
664 public:
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_; }
673 private:
674 // Overridden from ViewObserver:
675 void OnTreeChanged(const TreeChangeParams& params) override {
676 if (params.target == view_ && !params.new_parent)
677 was_removed_ = true;
680 View* view_;
681 bool was_removed_;
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);
758 Embed(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());
796 } // namespace mojo