Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(893)

Side by Side Diff: mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc

Issue 790623003: Restructure public side of view_manager service. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: BUILD.gn file reorderings Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "mojo/services/public/cpp/view_manager/view_manager.h"
6
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "mojo/application_manager/application_manager.h"
11 #include "mojo/public/cpp/application/application_connection.h"
12 #include "mojo/public/cpp/application/application_delegate.h"
13 #include "mojo/public/cpp/application/application_impl.h"
14 #include "mojo/public/cpp/application/service_provider_impl.h"
15 #include "mojo/public/interfaces/application/service_provider.mojom.h"
16 #include "mojo/services/public/cpp/geometry/geometry_util.h"
17 #include "mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h"
18 #include "mojo/services/public/cpp/view_manager/lib/view_private.h"
19 #include "mojo/services/public/cpp/view_manager/util.h"
20 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
21 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
22 #include "mojo/services/public/cpp/view_manager/view_observer.h"
23 #include "shell/shell_test_helper.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace mojo {
27
28 namespace {
29
30 const char kWindowManagerURL[] = "mojo:window_manager";
31 const char kEmbeddedApp1URL[] = "mojo:embedded_app_1";
32
33 base::RunLoop* current_run_loop = NULL;
34
35 void DoRunLoop() {
36 base::RunLoop run_loop;
37 current_run_loop = &run_loop;
38 current_run_loop->Run();
39 current_run_loop = NULL;
40 }
41
42 void QuitRunLoop() {
43 current_run_loop->Quit();
44 }
45
46 class ConnectApplicationLoader : public ApplicationLoader,
47 public ApplicationDelegate,
48 public ViewManagerDelegate {
49 public:
50 typedef base::Callback<void(ViewManager*, View*)> LoadedCallback;
51
52 explicit ConnectApplicationLoader(const LoadedCallback& callback)
53 : callback_(callback) {}
54 ~ConnectApplicationLoader() override {}
55
56 private:
57 // Overridden from ApplicationDelegate:
58 void Initialize(ApplicationImpl* app) override {
59 view_manager_client_factory_.reset(
60 new ViewManagerClientFactory(app->shell(), this));
61 }
62
63 // Overridden from ApplicationLoader:
64 void Load(ApplicationManager* manager,
65 const GURL& url,
66 ScopedMessagePipeHandle shell_handle,
67 LoadCallback callback) override {
68 ASSERT_TRUE(shell_handle.is_valid());
69 scoped_ptr<ApplicationImpl> app(
70 new ApplicationImpl(this, shell_handle.Pass()));
71 apps_.push_back(app.release());
72 }
73
74 void OnApplicationError(ApplicationManager* manager,
75 const GURL& url) override {}
76
77 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
78 connection->AddService(view_manager_client_factory_.get());
79 return true;
80 }
81
82 // Overridden from ViewManagerDelegate:
83 void OnEmbed(ViewManager* view_manager,
84 View* root,
85 ServiceProviderImpl* exported_services,
86 scoped_ptr<ServiceProvider> imported_services) override {
87 callback_.Run(view_manager, root);
88 }
89 void OnViewManagerDisconnected(ViewManager* view_manager) override {}
90
91 ScopedVector<ApplicationImpl> apps_;
92 LoadedCallback callback_;
93 scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_;
94
95 DISALLOW_COPY_AND_ASSIGN(ConnectApplicationLoader);
96 };
97
98 class BoundsChangeObserver : public ViewObserver {
99 public:
100 explicit BoundsChangeObserver(View* view) : view_(view) {}
101 ~BoundsChangeObserver() override {}
102
103 private:
104 // Overridden from ViewObserver:
105 void OnViewBoundsChanged(View* view,
106 const Rect& old_bounds,
107 const Rect& new_bounds) override {
108 DCHECK_EQ(view, view_);
109 QuitRunLoop();
110 }
111
112 View* view_;
113
114 DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
115 };
116
117 // Wait until the bounds of the supplied view change.
118 void WaitForBoundsToChange(View* view) {
119 BoundsChangeObserver observer(view);
120 view->AddObserver(&observer);
121 DoRunLoop();
122 view->RemoveObserver(&observer);
123 }
124
125 // Spins a runloop until the tree beginning at |root| has |tree_size| views
126 // (including |root|).
127 class TreeSizeMatchesObserver : public ViewObserver {
128 public:
129 TreeSizeMatchesObserver(View* tree, size_t tree_size)
130 : tree_(tree),
131 tree_size_(tree_size) {}
132 ~TreeSizeMatchesObserver() override {}
133
134 bool IsTreeCorrectSize() {
135 return CountViews(tree_) == tree_size_;
136 }
137
138 private:
139 // Overridden from ViewObserver:
140 void OnTreeChanged(const TreeChangeParams& params) override {
141 if (IsTreeCorrectSize())
142 QuitRunLoop();
143 }
144
145 size_t CountViews(const View* view) const {
146 size_t count = 1;
147 View::Children::const_iterator it = view->children().begin();
148 for (; it != view->children().end(); ++it)
149 count += CountViews(*it);
150 return count;
151 }
152
153 View* tree_;
154 size_t tree_size_;
155
156 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver);
157 };
158
159 void WaitForTreeSizeToMatch(View* view, size_t tree_size) {
160 TreeSizeMatchesObserver observer(view, tree_size);
161 if (observer.IsTreeCorrectSize())
162 return;
163 view->AddObserver(&observer);
164 DoRunLoop();
165 view->RemoveObserver(&observer);
166 }
167
168 // Utility class that waits for the destruction of some number of views and
169 // views.
170 class DestructionObserver : public ViewObserver {
171 public:
172 // |views| or |views| can be NULL.
173 explicit DestructionObserver(std::set<Id>* views) : views_(views) {}
174
175 private:
176 // Overridden from ViewObserver:
177 void OnViewDestroyed(View* view) override {
178 std::set<Id>::iterator it = views_->find(view->id());
179 if (it != views_->end())
180 views_->erase(it);
181 if (CanQuit())
182 QuitRunLoop();
183 }
184
185 bool CanQuit() {
186 return !views_ || views_->empty();
187 }
188
189 std::set<Id>* views_;
190
191 DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
192 };
193
194 void WaitForDestruction(ViewManager* view_manager, std::set<Id>* views) {
195 DestructionObserver observer(views);
196 DCHECK(views);
197 if (views) {
198 for (std::set<Id>::const_iterator it = views->begin();
199 it != views->end(); ++it) {
200 view_manager->GetViewById(*it)->AddObserver(&observer);
201 }
202 }
203 DoRunLoop();
204 }
205
206 class OrderChangeObserver : public ViewObserver {
207 public:
208 OrderChangeObserver(View* view) : view_(view) {
209 view_->AddObserver(this);
210 }
211 ~OrderChangeObserver() override { view_->RemoveObserver(this); }
212
213 private:
214 // Overridden from ViewObserver:
215 void OnViewReordered(View* view,
216 View* relative_view,
217 OrderDirection direction) override {
218 DCHECK_EQ(view, view_);
219 QuitRunLoop();
220 }
221
222 View* view_;
223
224 DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
225 };
226
227 void WaitForOrderChange(ViewManager* view_manager, View* view) {
228 OrderChangeObserver observer(view);
229 DoRunLoop();
230 }
231
232 // Tracks a view's destruction. Query is_valid() for current state.
233 class ViewTracker : public ViewObserver {
234 public:
235 explicit ViewTracker(View* view) : view_(view) {
236 view_->AddObserver(this);
237 }
238 ~ViewTracker() override {
239 if (view_)
240 view_->RemoveObserver(this);
241 }
242
243 bool is_valid() const { return !!view_; }
244
245 private:
246 // Overridden from ViewObserver:
247 void OnViewDestroyed(View* view) override {
248 DCHECK_EQ(view, view_);
249 view_ = NULL;
250 }
251
252 int id_;
253 View* view_;
254
255 DISALLOW_COPY_AND_ASSIGN(ViewTracker);
256 };
257
258 } // namespace
259
260 // ViewManager -----------------------------------------------------------------
261
262 // These tests model synchronization of two peer connections to the view manager
263 // service, that are given access to some root view.
264
265 class ViewManagerTest : public testing::Test {
266 public:
267 ViewManagerTest()
268 : connect_loop_(NULL),
269 loaded_view_manager_(NULL),
270 window_manager_(NULL),
271 commit_count_(0) {}
272
273 protected:
274 ViewManager* window_manager() { return window_manager_; }
275
276 View* CreateViewInParent(View* parent) {
277 ViewManager* parent_manager = ViewPrivate(parent).view_manager();
278 View* view = View::Create(parent_manager);
279 view->SetVisible(true);
280 parent->AddChild(view);
281 return view;
282 }
283
284 // Embeds another version of the test app @ view.
285 ViewManager* Embed(ViewManager* view_manager, View* view) {
286 DCHECK_EQ(view_manager, ViewPrivate(view).view_manager());
287 view->Embed(kEmbeddedApp1URL);
288 RunRunLoop();
289 return GetLoadedViewManager();
290 }
291
292 ViewManager* GetLoadedViewManager() {
293 ViewManager* view_manager = loaded_view_manager_;
294 loaded_view_manager_ = NULL;
295 return view_manager;
296 }
297
298 void UnloadApplication(const GURL& url) {
299 test_helper_.SetLoaderForURL(scoped_ptr<ApplicationLoader>(), url);
300 }
301
302 private:
303 // Overridden from testing::Test:
304 void SetUp() override {
305 ConnectApplicationLoader::LoadedCallback ready_callback = base::Bind(
306 &ViewManagerTest::OnViewManagerLoaded, base::Unretained(this));
307 test_helper_.Init();
308 test_helper_.SetLoaderForURL(
309 scoped_ptr<ApplicationLoader>(
310 new ConnectApplicationLoader(ready_callback)),
311 GURL(kWindowManagerURL));
312 test_helper_.SetLoaderForURL(
313 scoped_ptr<ApplicationLoader>(
314 new ConnectApplicationLoader(ready_callback)),
315 GURL(kEmbeddedApp1URL));
316
317 // TODO(sky): resolve this. Need to establish initial connection.
318 }
319
320 void OnViewManagerLoaded(ViewManager* view_manager, View* root) {
321 loaded_view_manager_ = view_manager;
322 connect_loop_->Quit();
323 }
324
325 void RunRunLoop() {
326 base::RunLoop run_loop;
327 connect_loop_ = &run_loop;
328 connect_loop_->Run();
329 connect_loop_ = NULL;
330 }
331
332 base::RunLoop* connect_loop_;
333 shell::ShellTestHelper test_helper_;
334 // Used to receive the most recent view manager loaded by an embed action.
335 ViewManager* loaded_view_manager_;
336 // The View Manager connection held by the window manager (app running at the
337 // root view).
338 ViewManager* window_manager_;
339 int commit_count_;
340
341 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
342 };
343
344 // TODO(sky): all of these tests are disabled as each test triggers running
345 // ViewsInit, which tries to register the same set of paths with the
346 // PathService, triggering a DCHECK.
347 TEST_F(ViewManagerTest, DISABLED_SetUp) {}
348
349 TEST_F(ViewManagerTest, DISABLED_Embed) {
350 View* view = View::Create(window_manager());
351 view->SetVisible(true);
352 window_manager()->GetRoots().front()->AddChild(view);
353 ViewManager* embedded = Embed(window_manager(), view);
354 EXPECT_TRUE(NULL != embedded);
355
356 View* view_in_embedded = embedded->GetRoots().front();
357 EXPECT_EQ(view->parent(), window_manager()->GetRoots().front());
358 EXPECT_EQ(NULL, view_in_embedded->parent());
359 }
360
361 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see
362 // N11.
363 // TODO(sky): Update client lib to match server.
364 TEST_F(ViewManagerTest, DISABLED_EmbeddedDoesntSeeChild) {
365 View* view = View::Create(window_manager());
366 view->SetVisible(true);
367 window_manager()->GetRoots().front()->AddChild(view);
368 View* nested = View::Create(window_manager());
369 nested->SetVisible(true);
370 view->AddChild(nested);
371
372 ViewManager* embedded = Embed(window_manager(), view);
373 EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(),
374 nested->id());
375 EXPECT_TRUE(embedded->GetRoots().front()->children().empty());
376 EXPECT_TRUE(nested->parent() == NULL);
377 }
378
379 // http://crbug.com/396300
380 TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupView) {
381 View* view = View::Create(window_manager());
382 view->SetVisible(true);
383 window_manager()->GetRoots().front()->AddChild(view);
384 ViewManager* embedded = Embed(window_manager(), view);
385
386 Id view_id = view->id();
387
388 UnloadApplication(GURL(kWindowManagerURL));
389
390 std::set<Id> views;
391 views.insert(view_id);
392 WaitForDestruction(embedded, &views);
393
394 EXPECT_TRUE(embedded->GetRoots().empty());
395 }
396
397 // TODO(beng): write a replacement test for the one that once existed here:
398 // This test validates the following scenario:
399 // - a view originating from one connection
400 // - a view originating from a second connection
401 // + the connection originating the view is destroyed
402 // -> the view should still exist (since the second connection is live) but
403 // should be disconnected from any views.
404 // http://crbug.com/396300
405 //
406 // TODO(beng): The new test should validate the scenario as described above
407 // except that the second connection still has a valid tree.
408
409 // Verifies that bounds changes applied to a view hierarchy in one connection
410 // are reflected to another.
411 TEST_F(ViewManagerTest, DISABLED_SetBounds) {
412 View* view = View::Create(window_manager());
413 view->SetVisible(true);
414 window_manager()->GetRoots().front()->AddChild(view);
415 ViewManager* embedded = Embed(window_manager(), view);
416
417 View* view_in_embedded = embedded->GetViewById(view->id());
418 EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
419
420 Rect rect;
421 rect.width = rect.height = 100;
422 view->SetBounds(rect);
423 EXPECT_NE(view->bounds(), view_in_embedded->bounds());
424 WaitForBoundsToChange(view_in_embedded);
425 EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
426 }
427
428 // Verifies that bounds changes applied to a view owned by a different
429 // connection are refused.
430 TEST_F(ViewManagerTest, DISABLED_SetBoundsSecurity) {
431 View* view = View::Create(window_manager());
432 view->SetVisible(true);
433 window_manager()->GetRoots().front()->AddChild(view);
434 ViewManager* embedded = Embed(window_manager(), view);
435
436 View* view_in_embedded = embedded->GetViewById(view->id());
437 Rect rect;
438 rect.width = 800;
439 rect.height = 600;
440 view->SetBounds(rect);
441 WaitForBoundsToChange(view_in_embedded);
442
443 rect.width = 1024;
444 rect.height = 768;
445 view_in_embedded->SetBounds(rect);
446 // Bounds change should have been rejected.
447 EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
448 }
449
450 // Verifies that a view can only be destroyed by the connection that created it.
451 TEST_F(ViewManagerTest, DISABLED_DestroySecurity) {
452 View* view = View::Create(window_manager());
453 view->SetVisible(true);
454 window_manager()->GetRoots().front()->AddChild(view);
455 ViewManager* embedded = Embed(window_manager(), view);
456
457 View* view_in_embedded = embedded->GetViewById(view->id());
458
459 ViewTracker tracker2(view_in_embedded);
460 view_in_embedded->Destroy();
461 // View should not have been destroyed.
462 EXPECT_TRUE(tracker2.is_valid());
463
464 ViewTracker tracker1(view);
465 view->Destroy();
466 EXPECT_FALSE(tracker1.is_valid());
467 }
468
469 TEST_F(ViewManagerTest, DISABLED_MultiRoots) {
470 View* view1 = View::Create(window_manager());
471 view1->SetVisible(true);
472 window_manager()->GetRoots().front()->AddChild(view1);
473 View* view2 = View::Create(window_manager());
474 view2->SetVisible(true);
475 window_manager()->GetRoots().front()->AddChild(view2);
476 ViewManager* embedded1 = Embed(window_manager(), view1);
477 ViewManager* embedded2 = Embed(window_manager(), view2);
478 EXPECT_EQ(embedded1, embedded2);
479 }
480
481 TEST_F(ViewManagerTest, DISABLED_EmbeddingIdentity) {
482 View* view = View::Create(window_manager());
483 view->SetVisible(true);
484 window_manager()->GetRoots().front()->AddChild(view);
485 ViewManager* embedded = Embed(window_manager(), view);
486 EXPECT_EQ(kWindowManagerURL, embedded->GetEmbedderURL());
487 }
488
489 TEST_F(ViewManagerTest, DISABLED_Reorder) {
490 View* view1 = View::Create(window_manager());
491 view1->SetVisible(true);
492 window_manager()->GetRoots().front()->AddChild(view1);
493
494 ViewManager* embedded = Embed(window_manager(), view1);
495
496 View* view11 = View::Create(embedded);
497 view11->SetVisible(true);
498 embedded->GetRoots().front()->AddChild(view11);
499 View* view12 = View::Create(embedded);
500 view12->SetVisible(true);
501 embedded->GetRoots().front()->AddChild(view12);
502
503 View* view1_in_wm = window_manager()->GetViewById(view1->id());
504
505 {
506 WaitForTreeSizeToMatch(view1, 2u);
507 view11->MoveToFront();
508 WaitForOrderChange(window_manager(),
509 window_manager()->GetViewById(view11->id()));
510
511 EXPECT_EQ(view1_in_wm->children().front(),
512 window_manager()->GetViewById(view12->id()));
513 EXPECT_EQ(view1_in_wm->children().back(),
514 window_manager()->GetViewById(view11->id()));
515 }
516
517 {
518 view11->MoveToBack();
519 WaitForOrderChange(window_manager(),
520 window_manager()->GetViewById(view11->id()));
521
522 EXPECT_EQ(view1_in_wm->children().front(),
523 window_manager()->GetViewById(view11->id()));
524 EXPECT_EQ(view1_in_wm->children().back(),
525 window_manager()->GetViewById(view12->id()));
526 }
527 }
528
529 namespace {
530
531 class VisibilityChangeObserver : public ViewObserver {
532 public:
533 explicit VisibilityChangeObserver(View* view) : view_(view) {
534 view_->AddObserver(this);
535 }
536 ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
537
538 private:
539 // Overridden from ViewObserver:
540 void OnViewVisibilityChanged(View* view) override {
541 EXPECT_EQ(view, view_);
542 QuitRunLoop();
543 }
544
545 View* view_;
546
547 DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
548 };
549
550 } // namespace
551
552 TEST_F(ViewManagerTest, DISABLED_Visible) {
553 View* view1 = View::Create(window_manager());
554 view1->SetVisible(true);
555 window_manager()->GetRoots().front()->AddChild(view1);
556
557 // Embed another app and verify initial state.
558 ViewManager* embedded = Embed(window_manager(), view1);
559 ASSERT_EQ(1u, embedded->GetRoots().size());
560 View* embedded_root = embedded->GetRoots().front();
561 EXPECT_TRUE(embedded_root->visible());
562 EXPECT_TRUE(embedded_root->IsDrawn());
563
564 // Change the visible state from the first connection and verify its mirrored
565 // correctly to the embedded app.
566 {
567 VisibilityChangeObserver observer(embedded_root);
568 view1->SetVisible(false);
569 DoRunLoop();
570 }
571
572 EXPECT_FALSE(view1->visible());
573 EXPECT_FALSE(view1->IsDrawn());
574
575 EXPECT_FALSE(embedded_root->visible());
576 EXPECT_FALSE(embedded_root->IsDrawn());
577
578 // Make the node visible again.
579 {
580 VisibilityChangeObserver observer(embedded_root);
581 view1->SetVisible(true);
582 DoRunLoop();
583 }
584
585 EXPECT_TRUE(view1->visible());
586 EXPECT_TRUE(view1->IsDrawn());
587
588 EXPECT_TRUE(embedded_root->visible());
589 EXPECT_TRUE(embedded_root->IsDrawn());
590 }
591
592 namespace {
593
594 class DrawnChangeObserver : public ViewObserver {
595 public:
596 explicit DrawnChangeObserver(View* view) : view_(view) {
597 view_->AddObserver(this);
598 }
599 ~DrawnChangeObserver() override { view_->RemoveObserver(this); }
600
601 private:
602 // Overridden from ViewObserver:
603 void OnViewDrawnChanged(View* view) override {
604 EXPECT_EQ(view, view_);
605 QuitRunLoop();
606 }
607
608 View* view_;
609
610 DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
611 };
612
613 } // namespace
614
615 TEST_F(ViewManagerTest, DISABLED_Drawn) {
616 View* view1 = View::Create(window_manager());
617 view1->SetVisible(true);
618 window_manager()->GetRoots().front()->AddChild(view1);
619
620 // Embed another app and verify initial state.
621 ViewManager* embedded = Embed(window_manager(), view1);
622 ASSERT_EQ(1u, embedded->GetRoots().size());
623 View* embedded_root = embedded->GetRoots().front();
624 EXPECT_TRUE(embedded_root->visible());
625 EXPECT_TRUE(embedded_root->IsDrawn());
626
627 // Change the visibility of the root, this should propagate a drawn state
628 // change to |embedded|.
629 {
630 DrawnChangeObserver observer(embedded_root);
631 window_manager()->GetRoots().front()->SetVisible(false);
632 DoRunLoop();
633 }
634
635 EXPECT_TRUE(view1->visible());
636 EXPECT_FALSE(view1->IsDrawn());
637
638 EXPECT_TRUE(embedded_root->visible());
639 EXPECT_FALSE(embedded_root->IsDrawn());
640 }
641
642 // TODO(beng): tests for view event dispatcher.
643 // - verify that we see events for all views.
644
645 // TODO(beng): tests for focus:
646 // - focus between two views known to a connection
647 // - focus between views unknown to one of the connections.
648 // - focus between views unknown to either connection.
649
650 // TODO(sky): need test of root being destroyed with existing views. See
651 // 434555 for specific case.
652
653 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/public/cpp/view_manager/tests/DEPS ('k') | mojo/services/public/cpp/view_manager/tests/view_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698