Update broken references to image assets
[chromium-blink-merge.git] / components / view_manager / view_manager_client_apptest.cc
blobf0642688da5516002d9a271f099584d3230eaccd
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| 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 {
105 public:
106 OrderChangeObserver(View* view) : view_(view) { view_->AddObserver(this); }
107 ~OrderChangeObserver() override { view_->RemoveObserver(this); }
109 private:
110 // Overridden from ViewObserver:
111 void OnViewReordered(View* view,
112 View* relative_view,
113 OrderDirection direction) override {
114 DCHECK_EQ(view, view_);
115 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
118 View* view_;
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 {
131 public:
132 explicit ViewTracker(View* view) : view_(view) { view_->AddObserver(this); }
133 ~ViewTracker() override {
134 if (view_)
135 view_->RemoveObserver(this);
138 bool is_valid() const { return !!view_; }
140 private:
141 // Overridden from ViewObserver:
142 void OnViewDestroyed(View* view) override {
143 DCHECK_EQ(view, view_);
144 view_ = nullptr;
147 View* view_;
149 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker);
152 } // namespace
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 {
160 public:
161 ViewManagerTest()
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
173 // returned.
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);
205 } else {
206 EXPECT_TRUE(QuitRunLoop());
210 private:
211 enum class EmbedType {
212 ALLOW_REEMBED,
213 NO_REEMBED,
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());
222 } else {
223 ConnectToApplicationAndEmbed(view);
225 if (!ViewManagerTestBase::DoRunLoopWithTimeout())
226 return nullptr;
227 ViewManager* vm = nullptr;
228 std::swap(vm, most_recent_view_manager_);
229 return vm;
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
262 // N11.
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());
305 Rect rect;
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());
322 Rect rect;
323 rect.width = 800;
324 rect.height = 600;
325 view->SetBounds(rect);
326 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
328 rect.width = 1024;
329 rect.height = 768;
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);
351 view->Destroy();
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()));
411 namespace {
413 class VisibilityChangeObserver : public ViewObserver {
414 public:
415 explicit VisibilityChangeObserver(View* view) : view_(view) {
416 view_->AddObserver(this);
418 ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
420 private:
421 // Overridden from ViewObserver:
422 void OnViewVisibilityChanged(View* view) override {
423 EXPECT_EQ(view, view_);
424 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
427 View* view_;
429 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
432 } // namespace
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());
475 namespace {
477 class DrawnChangeObserver : public ViewObserver {
478 public:
479 explicit DrawnChangeObserver(View* view) : view_(view) {
480 view_->AddObserver(this);
482 ~DrawnChangeObserver() override { view_->RemoveObserver(this); }
484 private:
485 // Overridden from ViewObserver:
486 void OnViewDrawnChanged(View* view) override {
487 EXPECT_EQ(view, view_);
488 EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
491 View* view_;
493 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
496 } // namespace
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.
529 namespace {
531 class FocusChangeObserver : public ViewObserver {
532 public:
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_; }
543 private:
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());
551 View* view_;
552 View* last_gained_focus_;
553 View* last_lost_focus_;
555 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
558 } // namespace
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);
583 view11->SetFocus();
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());
592 namespace {
594 class DestroyedChangedObserver : public ViewObserver {
595 public:
596 DestroyedChangedObserver(ViewManagerTestBase* test,
597 View* view,
598 bool* got_destroy)
599 : test_(test), view_(view), got_destroy_(got_destroy) {
600 view_->AddObserver(this);
602 ~DestroyedChangedObserver() override {
603 if (view_)
604 view_->RemoveObserver(this);
607 private:
608 // Overridden from ViewObserver:
609 void OnViewDestroyed(View* view) override {
610 EXPECT_EQ(view, view_);
611 view_->RemoveObserver(this);
612 *got_destroy_ = true;
613 view_ = nullptr;
615 // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
616 EXPECT_FALSE(test_->view_manager_destroyed());
619 ViewManagerTestBase* test_;
620 View* view_;
621 bool* got_destroy_;
623 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver);
626 } // namespace
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(),
638 &got_destroy);
639 delete view_manager;
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
645 // ViewManager.
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.
655 bool got_destroy;
656 DestroyedChangedObserver observer(this, embedded_view, &got_destroy);
657 EXPECT_FALSE(view_manager_destroyed());
658 Embed(view);
659 EXPECT_TRUE(view_manager_destroyed());
662 class ViewRemovedFromParentObserver : public ViewObserver {
663 public:
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_; }
672 private:
673 // Overridden from ViewObserver:
674 void OnTreeChanged(const TreeChangeParams& params) override {
675 if (params.target == view_ && !params.new_parent)
676 was_removed_ = true;
679 View* view_;
680 bool was_removed_;
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);
757 Embed(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());
795 namespace {
797 class DestroyObserver : public ViewObserver {
798 public:
799 DestroyObserver(ViewManagerTestBase* test, ViewManager* vm, bool* got_destroy)
800 : test_(test), got_destroy_(got_destroy) {
801 vm->GetRoot()->AddObserver(this);
803 ~DestroyObserver() override {}
805 private:
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_;
818 bool* got_destroy_;
820 MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyObserver);
823 } // namespace
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
844 // connection.
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);
850 vm2->SetEmbedRoot();
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);
867 vm2->SetEmbedRoot();
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));
884 } // namespace mojo