Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / components / view_manager / view_manager_client_apptest.cc
blob960625e0370f6aa4b11c1592dc6127d0f541ea93
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"
19 namespace mojo {
21 namespace {
23 class BoundsChangeObserver : public ViewObserver {
24 public:
25 explicit BoundsChangeObserver(View* view) : view_(view) {
26 view_->AddObserver(this);
28 ~BoundsChangeObserver() override { view_->RemoveObserver(this); }
30 private:
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());
39 View* view_;
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
51 // root.
52 bool IncrementWidthAndWaitForChange(View* view, ViewManager* other_vm) {
53 mojo::Rect bounds = view->bounds();
54 bounds.width++;
55 view->SetBounds(bounds);
56 View* view_in_vm = other_vm->GetRoot();
57 if (view_in_vm == view || view_in_vm->id() != view->id())
58 return false;
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 {
65 public:
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_; }
74 private:
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 {
82 size_t count = 1;
83 View::Children::const_iterator it = view->children().begin();
84 for (; it != view->children().end(); ++it)
85 count += CountViews(*it);
86 return count;
89 View* tree_;
90 size_t tree_size_;
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 {
103 public:
104 OrderChangeObserver(View* view) : view_(view) { view_->AddObserver(this); }
105 ~OrderChangeObserver() override { view_->RemoveObserver(this); }
107 private:
108 // Overridden from ViewObserver:
109 void OnViewReordered(View* view,
110 View* relative_view,
111 OrderDirection direction) override {
112 DCHECK_EQ(view, view_);
113 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
116 View* view_;
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 {
129 public:
130 explicit ViewTracker(View* view) : view_(view) { view_->AddObserver(this); }
131 ~ViewTracker() override {
132 if (view_)
133 view_->RemoveObserver(this);
136 bool is_valid() const { return !!view_; }
138 private:
139 // Overridden from ViewObserver:
140 void OnViewDestroyed(View* view) override {
141 DCHECK_EQ(view, view_);
142 view_ = nullptr;
145 View* view_;
147 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker);
150 } // namespace
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 {
158 public:
159 ViewManagerTest()
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
171 // returned.
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);
203 } else {
204 EXPECT_TRUE(QuitRunLoop());
208 private:
209 enum class EmbedType {
210 ALLOW_REEMBED,
211 NO_REEMBED,
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());
220 } else {
221 ConnectToApplicationAndEmbed(view);
223 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
224 return nullptr;
225 ViewManager* vm = nullptr;
226 std::swap(vm, most_recent_view_manager_);
227 return vm;
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
260 // N11.
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());
303 Rect rect;
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());
320 Rect rect;
321 rect.width = 800;
322 rect.height = 600;
323 view->SetBounds(rect);
324 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
326 rect.width = 1024;
327 rect.height = 768;
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);
349 view->Destroy();
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()));
409 namespace {
411 class VisibilityChangeObserver : public ViewObserver {
412 public:
413 explicit VisibilityChangeObserver(View* view) : view_(view) {
414 view_->AddObserver(this);
416 ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
418 private:
419 // Overridden from ViewObserver:
420 void OnViewVisibilityChanged(View* view) override {
421 EXPECT_EQ(view, view_);
422 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
425 View* view_;
427 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
430 } // namespace
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());
473 namespace {
475 class DrawnChangeObserver : public ViewObserver {
476 public:
477 explicit DrawnChangeObserver(View* view) : view_(view) {
478 view_->AddObserver(this);
480 ~DrawnChangeObserver() override { view_->RemoveObserver(this); }
482 private:
483 // Overridden from ViewObserver:
484 void OnViewDrawnChanged(View* view) override {
485 EXPECT_EQ(view, view_);
486 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
489 View* view_;
491 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
494 } // namespace
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.
527 namespace {
529 class FocusChangeObserver : public ViewObserver {
530 public:
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_; }
541 private:
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());
549 View* view_;
550 View* last_gained_focus_;
551 View* last_lost_focus_;
553 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
556 } // namespace
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);
581 view11->SetFocus();
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());
590 namespace {
592 class DestroyedChangedObserver : public ViewObserver {
593 public:
594 DestroyedChangedObserver(ViewManagerTestBase* test,
595 View* view,
596 bool* got_destroy)
597 : test_(test), view_(view), got_destroy_(got_destroy) {
598 view_->AddObserver(this);
600 ~DestroyedChangedObserver() override {
601 if (view_)
602 view_->RemoveObserver(this);
605 private:
606 // Overridden from ViewObserver:
607 void OnViewDestroyed(View* view) override {
608 EXPECT_EQ(view, view_);
609 view_->RemoveObserver(this);
610 *got_destroy_ = true;
611 view_ = nullptr;
613 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
614 EXPECT_FALSE(test_->view_manager_destroyed());
617 ViewManagerTestBase* test_;
618 View* view_;
619 bool* got_destroy_;
621 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver);
624 } // namespace
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(),
636 &got_destroy);
637 delete view_manager;
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
643 // ViewManager.
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.
653 bool got_destroy;
654 DestroyedChangedObserver observer(this, embedded_view, &got_destroy);
655 EXPECT_FALSE(view_manager_destroyed());
656 Embed(view);
657 EXPECT_TRUE(view_manager_destroyed());
660 class ViewRemovedFromParentObserver : public ViewObserver {
661 public:
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_; }
670 private:
671 // Overridden from ViewObserver:
672 void OnTreeChanged(const TreeChangeParams& params) override {
673 if (params.target == view_ && !params.new_parent)
674 was_removed_ = true;
677 View* view_;
678 bool was_removed_;
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);
755 Embed(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());
793 namespace {
795 class DestroyObserver : public ViewObserver {
796 public:
797 DestroyObserver(ViewManagerTestBase* test, ViewManager* vm, bool* got_destroy)
798 : test_(test), got_destroy_(got_destroy) {
799 vm->GetRoot()->AddObserver(this);
801 ~DestroyObserver() override {}
803 private:
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_;
816 bool* got_destroy_;
818 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyObserver);
821 } // namespace
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);
841 } // namespace mojo