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

Side by Side Diff: components/view_manager/view_tree_apptest.cc

Issue 1344573002: Mandoline: Rename components/view_manager to components/mus (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 5 years, 3 months 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 "base/bind.h"
6 #include "base/message_loop/message_loop.h"
7 #include "base/run_loop.h"
8 #include "base/strings/stringprintf.h"
9 #include "components/view_manager/ids.h"
10 #include "components/view_manager/public/interfaces/view_tree.mojom.h"
11 #include "components/view_manager/public/interfaces/view_tree_host.mojom.h"
12 #include "components/view_manager/test_change_tracker.h"
13 #include "mojo/application/public/cpp/application_delegate.h"
14 #include "mojo/application/public/cpp/application_impl.h"
15 #include "mojo/application/public/cpp/application_test_base.h"
16
17 using mojo::ApplicationConnection;
18 using mojo::ApplicationDelegate;
19 using mojo::Array;
20 using mojo::Callback;
21 using mojo::ConnectionSpecificId;
22 using mojo::ERROR_CODE_NONE;
23 using mojo::ErrorCode;
24 using mojo::EventPtr;
25 using mojo::Id;
26 using mojo::InterfaceRequest;
27 using mojo::ORDER_DIRECTION_ABOVE;
28 using mojo::ORDER_DIRECTION_BELOW;
29 using mojo::OrderDirection;
30 using mojo::RectPtr;
31 using mojo::ServiceProvider;
32 using mojo::ServiceProviderPtr;
33 using mojo::String;
34 using mojo::ViewDataPtr;
35 using mojo::ViewTree;
36 using mojo::ViewTreeClient;
37 using mojo::ViewportMetricsPtr;
38
39 namespace view_manager {
40
41 // Creates an id used for transport from the specified parameters.
42 Id BuildViewId(ConnectionSpecificId connection_id,
43 ConnectionSpecificId view_id) {
44 return (connection_id << 16) | view_id;
45 }
46
47 // Callback function from ViewTree functions. ----------------------------------
48
49 void BoolResultCallback(base::RunLoop* run_loop,
50 bool* result_cache,
51 bool result) {
52 *result_cache = result;
53 run_loop->Quit();
54 }
55
56 void ErrorCodeResultCallback(base::RunLoop* run_loop,
57 ErrorCode* result_cache,
58 ErrorCode result) {
59 *result_cache = result;
60 run_loop->Quit();
61 }
62
63 void ViewTreeResultCallback(base::RunLoop* run_loop,
64 std::vector<TestView>* views,
65 Array<ViewDataPtr> results) {
66 ViewDatasToTestViews(results, views);
67 run_loop->Quit();
68 }
69
70 void EmbedCallbackImpl(base::RunLoop* run_loop,
71 bool* result_cache,
72 bool result,
73 ConnectionSpecificId connection_id) {
74 *result_cache = result;
75 run_loop->Quit();
76 }
77
78 // -----------------------------------------------------------------------------
79
80 bool EmbedUrl(mojo::ApplicationImpl* app,
81 ViewTree* vm,
82 const String& url,
83 Id root_id) {
84 bool result = false;
85 base::RunLoop run_loop;
86 {
87 mojo::URLRequestPtr request(mojo::URLRequest::New());
88 request->url = mojo::String::From(url);
89 scoped_ptr<ApplicationConnection> connection =
90 app->ConnectToApplication(request.Pass());
91 mojo::ViewTreeClientPtr client;
92 connection->ConnectToService(&client);
93 vm->Embed(root_id, client.Pass(),
94 base::Bind(&EmbedCallbackImpl, &run_loop, &result));
95 }
96 run_loop.Run();
97 return result;
98 }
99
100 bool Embed(ViewTree* vm, Id root_id, mojo::ViewTreeClientPtr client) {
101 bool result = false;
102 base::RunLoop run_loop;
103 {
104 vm->Embed(root_id, client.Pass(),
105 base::Bind(&EmbedCallbackImpl, &run_loop, &result));
106 }
107 run_loop.Run();
108 return result;
109 }
110
111 ErrorCode CreateViewWithErrorCode(ViewTree* vm, Id view_id) {
112 ErrorCode result = ERROR_CODE_NONE;
113 base::RunLoop run_loop;
114 vm->CreateView(view_id,
115 base::Bind(&ErrorCodeResultCallback, &run_loop, &result));
116 run_loop.Run();
117 return result;
118 }
119
120 bool AddView(ViewTree* vm, Id parent, Id child) {
121 bool result = false;
122 base::RunLoop run_loop;
123 vm->AddView(parent, child,
124 base::Bind(&BoolResultCallback, &run_loop, &result));
125 run_loop.Run();
126 return result;
127 }
128
129 bool RemoveViewFromParent(ViewTree* vm, Id view_id) {
130 bool result = false;
131 base::RunLoop run_loop;
132 vm->RemoveViewFromParent(view_id,
133 base::Bind(&BoolResultCallback, &run_loop, &result));
134 run_loop.Run();
135 return result;
136 }
137
138 bool ReorderView(ViewTree* vm,
139 Id view_id,
140 Id relative_view_id,
141 OrderDirection direction) {
142 bool result = false;
143 base::RunLoop run_loop;
144 vm->ReorderView(view_id, relative_view_id, direction,
145 base::Bind(&BoolResultCallback, &run_loop, &result));
146 run_loop.Run();
147 return result;
148 }
149
150 void GetViewTree(ViewTree* vm,
151 Id view_id,
152 std::vector<TestView>* views) {
153 base::RunLoop run_loop;
154 vm->GetViewTree(view_id,
155 base::Bind(&ViewTreeResultCallback, &run_loop, views));
156 run_loop.Run();
157 }
158
159 bool DeleteView(ViewTree* vm, Id view_id) {
160 base::RunLoop run_loop;
161 bool result = false;
162 vm->DeleteView(view_id, base::Bind(&BoolResultCallback, &run_loop, &result));
163 run_loop.Run();
164 return result;
165 }
166
167 bool SetViewBounds(ViewTree* vm,
168 Id view_id,
169 int x,
170 int y,
171 int w,
172 int h) {
173 base::RunLoop run_loop;
174 bool result = false;
175 RectPtr rect(mojo::Rect::New());
176 rect->x = x;
177 rect->y = y;
178 rect->width = w;
179 rect->height = h;
180 vm->SetViewBounds(view_id, rect.Pass(),
181 base::Bind(&BoolResultCallback, &run_loop, &result));
182 run_loop.Run();
183 return result;
184 }
185
186 bool SetViewVisibility(ViewTree* vm, Id view_id, bool visible) {
187 base::RunLoop run_loop;
188 bool result = false;
189 vm->SetViewVisibility(view_id, visible,
190 base::Bind(&BoolResultCallback, &run_loop, &result));
191 run_loop.Run();
192 return result;
193 }
194
195 bool SetViewProperty(ViewTree* vm,
196 Id view_id,
197 const std::string& name,
198 const std::vector<uint8_t>* data) {
199 base::RunLoop run_loop;
200 bool result = false;
201 Array<uint8_t> mojo_data;
202 if (data)
203 mojo_data = Array<uint8_t>::From(*data);
204 vm->SetViewProperty(view_id, name, mojo_data.Pass(),
205 base::Bind(&BoolResultCallback, &run_loop, &result));
206 run_loop.Run();
207 return result;
208 }
209
210 // Utility functions -----------------------------------------------------------
211
212 // Waits for all messages to be received by |vm|. This is done by attempting to
213 // create a bogus view. When we get the response we know all messages have been
214 // processed.
215 bool WaitForAllMessages(ViewTree* vm) {
216 ErrorCode result = ERROR_CODE_NONE;
217 base::RunLoop run_loop;
218 vm->CreateView(ViewIdToTransportId(InvalidViewId()),
219 base::Bind(&ErrorCodeResultCallback, &run_loop, &result));
220 run_loop.Run();
221 return result != ERROR_CODE_NONE;
222 }
223
224 const Id kNullParentId = 0;
225 std::string IdToString(Id id) {
226 return (id == kNullParentId)
227 ? "null"
228 : base::StringPrintf("%d,%d", mojo::HiWord(id), mojo::LoWord(id));
229 }
230
231 std::string ViewParentToString(Id view, Id parent) {
232 return base::StringPrintf("view=%s parent=%s", IdToString(view).c_str(),
233 IdToString(parent).c_str());
234 }
235
236 // -----------------------------------------------------------------------------
237
238 // A ViewTreeClient implementation that logs all changes to a tracker.
239 class ViewTreeClientImpl : public mojo::ViewTreeClient,
240 public TestChangeTracker::Delegate {
241 public:
242 explicit ViewTreeClientImpl(mojo::ApplicationImpl* app)
243 : binding_(this), app_(app), connection_id_(0), root_view_id_(0) {
244 tracker_.set_delegate(this);
245 }
246
247 void Bind(mojo::InterfaceRequest<mojo::ViewTreeClient> request) {
248 binding_.Bind(request.Pass());
249 }
250
251 mojo::ViewTree* tree() { return tree_.get(); }
252 TestChangeTracker* tracker() { return &tracker_; }
253
254 // Runs a nested MessageLoop until |count| changes (calls to
255 // ViewTreeClient functions) have been received.
256 void WaitForChangeCount(size_t count) {
257 if (count == tracker_.changes()->size())
258 return;
259
260 ASSERT_TRUE(wait_state_.get() == nullptr);
261 wait_state_.reset(new WaitState);
262 wait_state_->change_count = count;
263 wait_state_->run_loop.Run();
264 wait_state_.reset();
265 }
266
267 // Runs a nested MessageLoop until OnEmbed() has been encountered.
268 void WaitForOnEmbed() {
269 if (tree_)
270 return;
271 embed_run_loop_.reset(new base::RunLoop);
272 embed_run_loop_->Run();
273 embed_run_loop_.reset();
274 }
275
276 bool WaitForIncomingMethodCall() {
277 return binding_.WaitForIncomingMethodCall();
278 }
279
280 Id CreateView(ConnectionSpecificId view_id) {
281 ErrorCode result = ERROR_CODE_NONE;
282 base::RunLoop run_loop;
283 Id id = BuildViewId(connection_id_, view_id);
284 tree()->CreateView(
285 id, base::Bind(&ErrorCodeResultCallback, &run_loop, &result));
286 run_loop.Run();
287 return result == ERROR_CODE_NONE ? id : 0;
288 }
289
290 void set_root_view(Id root_view_id) { root_view_id_ = root_view_id; }
291
292 private:
293 // Used when running a nested MessageLoop.
294 struct WaitState {
295 WaitState() : change_count(0) {}
296
297 // Number of changes waiting for.
298 size_t change_count;
299 base::RunLoop run_loop;
300 };
301
302 // TestChangeTracker::Delegate:
303 void OnChangeAdded() override {
304 if (wait_state_.get() &&
305 wait_state_->change_count == tracker_.changes()->size()) {
306 wait_state_->run_loop.Quit();
307 }
308 }
309
310 // ViewTreeClient:
311 void OnEmbed(ConnectionSpecificId connection_id,
312 ViewDataPtr root,
313 mojo::ViewTreePtr tree,
314 mojo::Id focused_view_id,
315 uint32_t access_policy) override {
316 // TODO(sky): add coverage of |focused_view_id|.
317 tree_ = tree.Pass();
318 connection_id_ = connection_id;
319 tracker()->OnEmbed(connection_id, root.Pass());
320 if (embed_run_loop_)
321 embed_run_loop_->Quit();
322 }
323 void OnEmbeddedAppDisconnected(Id view_id) override {
324 tracker()->OnEmbeddedAppDisconnected(view_id);
325 }
326 void OnUnembed() override { tracker()->OnUnembed(); }
327 void OnViewBoundsChanged(Id view_id,
328 RectPtr old_bounds,
329 RectPtr new_bounds) override {
330 // The bounds of the root may change during startup on Android at random
331 // times. As this doesn't matter, and shouldn't impact test exepctations,
332 // it is ignored.
333 if (view_id == root_view_id_)
334 return;
335 tracker()->OnViewBoundsChanged(view_id, old_bounds.Pass(),
336 new_bounds.Pass());
337 }
338 void OnViewViewportMetricsChanged(ViewportMetricsPtr old_metrics,
339 ViewportMetricsPtr new_metrics) override {
340 // Don't track the metrics as they are available at an indeterministic time
341 // on Android.
342 }
343 void OnViewHierarchyChanged(Id view,
344 Id new_parent,
345 Id old_parent,
346 Array<ViewDataPtr> views) override {
347 tracker()->OnViewHierarchyChanged(view, new_parent, old_parent,
348 views.Pass());
349 }
350 void OnViewReordered(Id view_id,
351 Id relative_view_id,
352 OrderDirection direction) override {
353 tracker()->OnViewReordered(view_id, relative_view_id, direction);
354 }
355 void OnViewDeleted(Id view) override { tracker()->OnViewDeleted(view); }
356 void OnViewVisibilityChanged(uint32_t view, bool visible) override {
357 tracker()->OnViewVisibilityChanged(view, visible);
358 }
359 void OnViewDrawnStateChanged(uint32_t view, bool drawn) override {
360 tracker()->OnViewDrawnStateChanged(view, drawn);
361 }
362 void OnViewInputEvent(Id view_id,
363 EventPtr event,
364 const Callback<void()>& callback) override {
365 tracker()->OnViewInputEvent(view_id, event.Pass());
366 callback.Run();
367 }
368 void OnViewSharedPropertyChanged(uint32_t view,
369 const String& name,
370 Array<uint8_t> new_data) override {
371 tracker_.OnViewSharedPropertyChanged(view, name, new_data.Pass());
372 }
373 // TODO(sky): add testing coverage.
374 void OnViewFocused(uint32_t focused_view_id) override {}
375
376 TestChangeTracker tracker_;
377
378 mojo::ViewTreePtr tree_;
379
380 // If non-null we're waiting for OnEmbed() using this RunLoop.
381 scoped_ptr<base::RunLoop> embed_run_loop_;
382
383 // If non-null we're waiting for a certain number of change notifications to
384 // be encountered.
385 scoped_ptr<WaitState> wait_state_;
386
387 mojo::Binding<ViewTreeClient> binding_;
388 mojo::ApplicationImpl* app_;
389 Id connection_id_;
390 Id root_view_id_;
391
392 DISALLOW_COPY_AND_ASSIGN(ViewTreeClientImpl);
393 };
394
395 // -----------------------------------------------------------------------------
396
397 // InterfaceFactory for vending ViewTreeClientImpls.
398 class ViewTreeClientFactory : public mojo::InterfaceFactory<ViewTreeClient> {
399 public:
400 explicit ViewTreeClientFactory(mojo::ApplicationImpl* app) : app_(app) {}
401 ~ViewTreeClientFactory() override {}
402
403 // Runs a nested MessageLoop until a new instance has been created.
404 scoped_ptr<ViewTreeClientImpl> WaitForInstance() {
405 if (!client_impl_.get()) {
406 DCHECK(!run_loop_.get());
407 run_loop_.reset(new base::RunLoop);
408 run_loop_->Run();
409 run_loop_.reset();
410 }
411 return client_impl_.Pass();
412 }
413
414 private:
415 // InterfaceFactory<ViewTreeClient>:
416 void Create(ApplicationConnection* connection,
417 InterfaceRequest<ViewTreeClient> request) override {
418 client_impl_.reset(new ViewTreeClientImpl(app_));
419 client_impl_->Bind(request.Pass());
420 if (run_loop_.get())
421 run_loop_->Quit();
422 }
423
424 mojo::ApplicationImpl* app_;
425 scoped_ptr<ViewTreeClientImpl> client_impl_;
426 scoped_ptr<base::RunLoop> run_loop_;
427
428 DISALLOW_COPY_AND_ASSIGN(ViewTreeClientFactory);
429 };
430
431 class ViewTreeAppTest : public mojo::test::ApplicationTestBase,
432 public ApplicationDelegate {
433 public:
434 ViewTreeAppTest()
435 : connection_id_1_(0), connection_id_2_(0), root_view_id_(0) {}
436 ~ViewTreeAppTest() override {}
437
438 protected:
439 // Returns the changes from the various connections.
440 std::vector<Change>* changes1() { return vm_client1_->tracker()->changes(); }
441 std::vector<Change>* changes2() { return vm_client2_->tracker()->changes(); }
442 std::vector<Change>* changes3() { return vm_client3_->tracker()->changes(); }
443
444 // Various connections. |vm1()|, being the first connection, has special
445 // permissions (it's treated as the window manager).
446 ViewTree* vm1() { return vm_client1_->tree(); }
447 ViewTree* vm2() { return vm_client2_->tree(); }
448 ViewTree* vm3() { return vm_client3_->tree(); }
449
450 ViewTreeClientImpl* vm_client1() { return vm_client1_.get(); }
451 ViewTreeClientImpl* vm_client2() { return vm_client2_.get(); }
452 ViewTreeClientImpl* vm_client3() { return vm_client3_.get(); }
453
454 Id root_view_id() const { return root_view_id_; }
455
456 int connection_id_1() const { return connection_id_1_; }
457 int connection_id_2() const { return connection_id_2_; }
458
459 void EstablishSecondConnectionWithRoot(Id root_id) {
460 ASSERT_TRUE(vm_client2_.get() == nullptr);
461 vm_client2_ =
462 EstablishConnectionViaEmbed(vm1(), root_id, &connection_id_2_);
463 ASSERT_GT(connection_id_2_, 0);
464 ASSERT_TRUE(vm_client2_.get() != nullptr);
465 vm_client2_->set_root_view(root_view_id_);
466 }
467
468 void EstablishSecondConnection(bool create_initial_view) {
469 Id view_1_1 = 0;
470 if (create_initial_view) {
471 view_1_1 = vm_client1()->CreateView(1);
472 ASSERT_TRUE(view_1_1);
473 }
474 ASSERT_NO_FATAL_FAILURE(
475 EstablishSecondConnectionWithRoot(BuildViewId(connection_id_1(), 1)));
476
477 if (create_initial_view) {
478 EXPECT_EQ("[" + ViewParentToString(view_1_1, kNullParentId) + "]",
479 ChangeViewDescription(*changes2()));
480 }
481 }
482
483 void EstablishThirdConnection(ViewTree* owner, Id root_id) {
484 ASSERT_TRUE(vm_client3_.get() == nullptr);
485 vm_client3_ = EstablishConnectionViaEmbed(owner, root_id, nullptr);
486 ASSERT_TRUE(vm_client3_.get() != nullptr);
487 vm_client3_->set_root_view(root_view_id_);
488 }
489
490 scoped_ptr<ViewTreeClientImpl> WaitForViewTreeClient() {
491 return client_factory_->WaitForInstance();
492 }
493
494 // Establishes a new connection by way of Embed() on the specified
495 // ViewTree.
496 scoped_ptr<ViewTreeClientImpl>
497 EstablishConnectionViaEmbed(ViewTree* owner, Id root_id, int* connection_id) {
498 if (!EmbedUrl(application_impl(), owner, application_impl()->url(),
499 root_id)) {
500 ADD_FAILURE() << "Embed() failed";
501 return nullptr;
502 }
503 scoped_ptr<ViewTreeClientImpl> client =
504 client_factory_->WaitForInstance();
505 if (!client.get()) {
506 ADD_FAILURE() << "WaitForInstance failed";
507 return nullptr;
508 }
509 client->WaitForOnEmbed();
510
511 EXPECT_EQ("OnEmbed",
512 SingleChangeToDescription(*client->tracker()->changes()));
513 if (connection_id)
514 *connection_id = (*client->tracker()->changes())[0].connection_id;
515 return client.Pass();
516 }
517
518 // ApplicationTestBase:
519 ApplicationDelegate* GetApplicationDelegate() override { return this; }
520 void SetUp() override {
521 ApplicationTestBase::SetUp();
522 client_factory_.reset(new ViewTreeClientFactory(application_impl()));
523 mojo::URLRequestPtr request(mojo::URLRequest::New());
524 request->url = mojo::String::From("mojo:view_manager");
525
526 mojo::ViewTreeHostFactoryPtr factory;
527 application_impl()->ConnectToService(request.Pass(), &factory);
528
529 mojo::ViewTreeClientPtr tree_client_ptr;
530 vm_client1_.reset(new ViewTreeClientImpl(application_impl()));
531 vm_client1_->Bind(GetProxy(&tree_client_ptr));
532
533 factory->CreateViewTreeHost(GetProxy(&host_),
534 mojo::ViewTreeHostClientPtr(),
535 tree_client_ptr.Pass());
536
537 // Next we should get an embed call on the "window manager" client.
538 vm_client1_->WaitForIncomingMethodCall();
539
540 ASSERT_EQ(1u, changes1()->size());
541 EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type);
542 // All these tests assume 1 for the client id. The only real assertion here
543 // is the client id is not zero, but adding this as rest of code here
544 // assumes 1.
545 ASSERT_GT((*changes1())[0].connection_id, 0);
546 connection_id_1_ = (*changes1())[0].connection_id;
547 ASSERT_FALSE((*changes1())[0].views.empty());
548 root_view_id_ = (*changes1())[0].views[0].view_id;
549 vm_client1_->set_root_view(root_view_id_);
550 changes1()->clear();
551 }
552
553 // ApplicationDelegate implementation.
554 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
555 connection->AddService(client_factory_.get());
556 return true;
557 }
558
559 scoped_ptr<ViewTreeClientImpl> vm_client1_;
560 scoped_ptr<ViewTreeClientImpl> vm_client2_;
561 scoped_ptr<ViewTreeClientImpl> vm_client3_;
562
563 mojo::ViewTreeHostPtr host_;
564
565 private:
566 scoped_ptr<ViewTreeClientFactory> client_factory_;
567 int connection_id_1_;
568 int connection_id_2_;
569 Id root_view_id_;
570
571 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTreeAppTest);
572 };
573
574 // Verifies two clients/connections get different ids.
575 TEST_F(ViewTreeAppTest, TwoClientsGetDifferentConnectionIds) {
576 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
577
578 ASSERT_EQ(1u, changes2()->size());
579 ASSERT_NE(connection_id_1(), connection_id_2());
580 }
581
582 // Verifies when Embed() is invoked any child views are removed.
583 TEST_F(ViewTreeAppTest, ViewsRemovedWhenEmbedding) {
584 // Two views 1 and 2. 2 is parented to 1.
585 Id view_1_1 = vm_client1()->CreateView(1);
586 ASSERT_TRUE(view_1_1);
587 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
588
589 Id view_1_2 = vm_client1()->CreateView(2);
590 ASSERT_TRUE(view_1_2);
591 ASSERT_TRUE(AddView(vm1(), view_1_1, view_1_2));
592
593 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
594 ASSERT_EQ(1u, changes2()->size());
595 ASSERT_EQ(1u, (*changes2())[0].views.size());
596 EXPECT_EQ("[" + ViewParentToString(view_1_1, kNullParentId) + "]",
597 ChangeViewDescription(*changes2()));
598
599 // Embed() removed view 2.
600 {
601 std::vector<TestView> views;
602 GetViewTree(vm1(), view_1_2, &views);
603 EXPECT_EQ(ViewParentToString(view_1_2, kNullParentId),
604 SingleViewDescription(views));
605 }
606
607 // vm2 should not see view 2.
608 {
609 std::vector<TestView> views;
610 GetViewTree(vm2(), view_1_1, &views);
611 EXPECT_EQ(ViewParentToString(view_1_1, kNullParentId),
612 SingleViewDescription(views));
613 }
614 {
615 std::vector<TestView> views;
616 GetViewTree(vm2(), view_1_2, &views);
617 EXPECT_TRUE(views.empty());
618 }
619
620 // Views 3 and 4 in connection 2.
621 Id view_2_3 = vm_client2()->CreateView(3);
622 Id view_2_4 = vm_client2()->CreateView(4);
623 ASSERT_TRUE(view_2_3);
624 ASSERT_TRUE(view_2_4);
625 ASSERT_TRUE(AddView(vm2(), view_2_3, view_2_4));
626
627 // Connection 3 rooted at 2.
628 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), view_2_3));
629
630 // View 4 should no longer have a parent.
631 {
632 std::vector<TestView> views;
633 GetViewTree(vm2(), view_2_3, &views);
634 EXPECT_EQ(ViewParentToString(view_2_3, kNullParentId),
635 SingleViewDescription(views));
636
637 views.clear();
638 GetViewTree(vm2(), view_2_4, &views);
639 EXPECT_EQ(ViewParentToString(view_2_4, kNullParentId),
640 SingleViewDescription(views));
641 }
642
643 // And view 4 should not be visible to connection 3.
644 {
645 std::vector<TestView> views;
646 GetViewTree(vm3(), view_2_3, &views);
647 EXPECT_EQ(ViewParentToString(view_2_3, kNullParentId),
648 SingleViewDescription(views));
649 }
650 }
651
652 // Verifies once Embed() has been invoked the parent connection can't see any
653 // children.
654 TEST_F(ViewTreeAppTest, CantAccessChildrenOfEmbeddedView) {
655 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
656
657 Id view_1_1 = BuildViewId(connection_id_1(), 1);
658 Id view_2_2 = vm_client2()->CreateView(2);
659 ASSERT_TRUE(view_2_2);
660 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
661
662 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), view_2_2));
663
664 Id view_3_3 = vm_client3()->CreateView(3);
665 ASSERT_TRUE(view_3_3);
666 ASSERT_TRUE(AddView(vm3(), view_2_2, view_3_3));
667
668 // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a
669 // different connection.
670 {
671 std::vector<TestView> views;
672 GetViewTree(vm2(), view_2_2, &views);
673 EXPECT_EQ(ViewParentToString(view_2_2, view_1_1),
674 SingleViewDescription(views));
675 }
676
677 // Connection 2 shouldn't be able to get view 3 at all.
678 {
679 std::vector<TestView> views;
680 GetViewTree(vm2(), view_3_3, &views);
681 EXPECT_TRUE(views.empty());
682 }
683
684 // Connection 1 should be able to see it all (its the root).
685 {
686 std::vector<TestView> views;
687 GetViewTree(vm1(), view_1_1, &views);
688 ASSERT_EQ(3u, views.size());
689 EXPECT_EQ(ViewParentToString(view_1_1, kNullParentId), views[0].ToString());
690 EXPECT_EQ(ViewParentToString(view_2_2, view_1_1), views[1].ToString());
691 EXPECT_EQ(ViewParentToString(view_3_3, view_2_2), views[2].ToString());
692 }
693 }
694
695 // Verifies once Embed() has been invoked the parent can't mutate the children.
696 TEST_F(ViewTreeAppTest, CantModifyChildrenOfEmbeddedView) {
697 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
698
699 Id view_1_1 = BuildViewId(connection_id_1(), 1);
700 Id view_2_2 = vm_client2()->CreateView(2);
701 ASSERT_TRUE(view_2_2);
702 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
703
704 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), view_2_2));
705
706 Id view_2_3 = vm_client2()->CreateView(3);
707 ASSERT_TRUE(view_2_3);
708 // Connection 2 shouldn't be able to add anything to the view anymore.
709 ASSERT_FALSE(AddView(vm2(), view_2_2, view_2_3));
710
711 // Create view 3 in connection 3 and add it to view 3.
712 Id view_3_3 = vm_client3()->CreateView(3);
713 ASSERT_TRUE(view_3_3);
714 ASSERT_TRUE(AddView(vm3(), view_2_2, view_3_3));
715
716 // Connection 2 shouldn't be able to remove view 3.
717 ASSERT_FALSE(RemoveViewFromParent(vm2(), view_3_3));
718 }
719
720 // Verifies client gets a valid id.
721 TEST_F(ViewTreeAppTest, CreateView) {
722 Id view_1_1 = vm_client1()->CreateView(1);
723 ASSERT_TRUE(view_1_1);
724 EXPECT_TRUE(changes1()->empty());
725
726 // Can't create a view with the same id.
727 ASSERT_EQ(mojo::ERROR_CODE_VALUE_IN_USE,
728 CreateViewWithErrorCode(vm1(), view_1_1));
729 EXPECT_TRUE(changes1()->empty());
730
731 // Can't create a view with a bogus connection id.
732 EXPECT_EQ(
733 mojo::ERROR_CODE_ILLEGAL_ARGUMENT,
734 CreateViewWithErrorCode(vm1(), BuildViewId(connection_id_1() + 1, 1)));
735 EXPECT_TRUE(changes1()->empty());
736 }
737
738 // Verifies AddView fails when view is already in position.
739 TEST_F(ViewTreeAppTest, AddViewWithNoChange) {
740 Id view_1_2 = vm_client1()->CreateView(2);
741 Id view_1_3 = vm_client1()->CreateView(3);
742 ASSERT_TRUE(view_1_2);
743 ASSERT_TRUE(view_1_3);
744
745 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
746
747 // Make 3 a child of 2.
748 ASSERT_TRUE(AddView(vm1(), view_1_2, view_1_3));
749
750 // Try again, this should fail.
751 EXPECT_FALSE(AddView(vm1(), view_1_2, view_1_3));
752 }
753
754 // Verifies AddView fails when view is already in position.
755 TEST_F(ViewTreeAppTest, AddAncestorFails) {
756 Id view_1_2 = vm_client1()->CreateView(2);
757 Id view_1_3 = vm_client1()->CreateView(3);
758 ASSERT_TRUE(view_1_2);
759 ASSERT_TRUE(view_1_3);
760
761 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
762
763 // Make 3 a child of 2.
764 ASSERT_TRUE(AddView(vm1(), view_1_2, view_1_3));
765
766 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
767 EXPECT_FALSE(AddView(vm1(), view_1_3, view_1_2));
768 }
769
770 // Verifies adding to root sends right notifications.
771 TEST_F(ViewTreeAppTest, AddToRoot) {
772 Id view_1_21 = vm_client1()->CreateView(21);
773 Id view_1_3 = vm_client1()->CreateView(3);
774 ASSERT_TRUE(view_1_21);
775 ASSERT_TRUE(view_1_3);
776
777 Id view_1_1 = BuildViewId(connection_id_1(), 1);
778 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
779 changes2()->clear();
780
781 // Make 3 a child of 21.
782 ASSERT_TRUE(AddView(vm1(), view_1_21, view_1_3));
783
784 // Make 21 a child of 1.
785 ASSERT_TRUE(AddView(vm1(), view_1_1, view_1_21));
786
787 // Connection 2 should not be told anything (because the view is from a
788 // different connection). Create a view to ensure we got a response from
789 // the server.
790 ASSERT_TRUE(vm_client2()->CreateView(100));
791 EXPECT_TRUE(changes2()->empty());
792 }
793
794 // Verifies HierarchyChanged is correctly sent for various adds/removes.
795 TEST_F(ViewTreeAppTest, ViewHierarchyChangedViews) {
796 // 1,2->1,11.
797 Id view_1_2 = vm_client1()->CreateView(2);
798 ASSERT_TRUE(view_1_2);
799 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_2, true));
800 Id view_1_11 = vm_client1()->CreateView(11);
801 ASSERT_TRUE(view_1_11);
802 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_11, true));
803 ASSERT_TRUE(AddView(vm1(), view_1_2, view_1_11));
804
805 Id view_1_1 = BuildViewId(connection_id_1(), 1);
806 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
807 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, true));
808
809 ASSERT_TRUE(WaitForAllMessages(vm2()));
810 changes2()->clear();
811
812 // 1,1->1,2->1,11
813 {
814 // Client 2 should not get anything (1,2 is from another connection).
815 ASSERT_TRUE(AddView(vm1(), view_1_1, view_1_2));
816 ASSERT_TRUE(WaitForAllMessages(vm2()));
817 EXPECT_TRUE(changes2()->empty());
818 }
819
820 // 0,1->1,1->1,2->1,11.
821 {
822 // Client 2 is now connected to the root, so it should have gotten a drawn
823 // notification.
824 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
825 vm_client2_->WaitForChangeCount(1u);
826 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_1) + " drawn=true",
827 SingleChangeToDescription(*changes2()));
828 }
829
830 // 1,1->1,2->1,11.
831 {
832 // Client 2 is no longer connected to the root, should get drawn state
833 // changed.
834 changes2()->clear();
835 ASSERT_TRUE(RemoveViewFromParent(vm1(), view_1_1));
836 vm_client2_->WaitForChangeCount(1);
837 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_1) + " drawn=false",
838 SingleChangeToDescription(*changes2()));
839 }
840
841 // 1,1->1,2->1,11->1,111.
842 Id view_1_111 = vm_client1()->CreateView(111);
843 ASSERT_TRUE(view_1_111);
844 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_111, true));
845 {
846 changes2()->clear();
847 ASSERT_TRUE(AddView(vm1(), view_1_11, view_1_111));
848 ASSERT_TRUE(WaitForAllMessages(vm2()));
849 EXPECT_TRUE(changes2()->empty());
850 }
851
852 // 0,1->1,1->1,2->1,11->1,111
853 {
854 changes2()->clear();
855 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
856 vm_client2_->WaitForChangeCount(1);
857 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_1) + " drawn=true",
858 SingleChangeToDescription(*changes2()));
859 }
860 }
861
862 TEST_F(ViewTreeAppTest, ViewHierarchyChangedAddingKnownToUnknown) {
863 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no
864 // parent).
865 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
866 Id view_1_1 = BuildViewId(connection_id_1(), 1);
867
868 Id view_2_11 = vm_client2()->CreateView(11);
869 Id view_2_2 = vm_client2()->CreateView(2);
870 Id view_2_21 = vm_client2()->CreateView(21);
871 ASSERT_TRUE(view_2_11);
872 ASSERT_TRUE(view_2_2);
873 ASSERT_TRUE(view_2_21);
874
875 // Set up the hierarchy.
876 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
877 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_11));
878 ASSERT_TRUE(AddView(vm2(), view_2_2, view_2_21));
879
880 // Remove 11, should result in a hierarchy change for the root.
881 {
882 changes1()->clear();
883 ASSERT_TRUE(RemoveViewFromParent(vm2(), view_2_11));
884
885 vm_client1_->WaitForChangeCount(1);
886 EXPECT_EQ("HierarchyChanged view=" + IdToString(view_2_11) +
887 " new_parent=null old_parent=" + IdToString(view_1_1),
888 SingleChangeToDescription(*changes1()));
889 }
890
891 // Add 2 to 1.
892 {
893 changes1()->clear();
894 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
895 vm_client1_->WaitForChangeCount(1);
896 EXPECT_EQ("HierarchyChanged view=" + IdToString(view_2_2) + " new_parent=" +
897 IdToString(view_1_1) + " old_parent=null",
898 SingleChangeToDescription(*changes1()));
899 EXPECT_EQ("[" + ViewParentToString(view_2_2, view_1_1) + "],[" +
900 ViewParentToString(view_2_21, view_2_2) + "]",
901 ChangeViewDescription(*changes1()));
902 }
903 }
904
905 TEST_F(ViewTreeAppTest, ReorderView) {
906 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
907
908 Id view_2_1 = vm_client2()->CreateView(1);
909 Id view_2_2 = vm_client2()->CreateView(2);
910 Id view_2_3 = vm_client2()->CreateView(3);
911 Id view_1_4 = vm_client1()->CreateView(4); // Peer to 1,1
912 Id view_1_5 = vm_client1()->CreateView(5); // Peer to 1,1
913 Id view_2_6 = vm_client2()->CreateView(6); // Child of 1,2.
914 Id view_2_7 = vm_client2()->CreateView(7); // Unparented.
915 Id view_2_8 = vm_client2()->CreateView(8); // Unparented.
916 ASSERT_TRUE(view_2_1);
917 ASSERT_TRUE(view_2_2);
918 ASSERT_TRUE(view_2_3);
919 ASSERT_TRUE(view_1_4);
920 ASSERT_TRUE(view_1_5);
921 ASSERT_TRUE(view_2_6);
922 ASSERT_TRUE(view_2_7);
923 ASSERT_TRUE(view_2_8);
924
925 ASSERT_TRUE(AddView(vm2(), view_2_1, view_2_2));
926 ASSERT_TRUE(AddView(vm2(), view_2_2, view_2_6));
927 ASSERT_TRUE(AddView(vm2(), view_2_1, view_2_3));
928 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_4));
929 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_5));
930 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_2_1));
931
932 {
933 changes1()->clear();
934 ASSERT_TRUE(ReorderView(vm2(), view_2_2, view_2_3, ORDER_DIRECTION_ABOVE));
935
936 vm_client1_->WaitForChangeCount(1);
937 EXPECT_EQ("Reordered view=" + IdToString(view_2_2) + " relative=" +
938 IdToString(view_2_3) + " direction=above",
939 SingleChangeToDescription(*changes1()));
940 }
941
942 {
943 changes1()->clear();
944 ASSERT_TRUE(ReorderView(vm2(), view_2_2, view_2_3, ORDER_DIRECTION_BELOW));
945
946 vm_client1_->WaitForChangeCount(1);
947 EXPECT_EQ("Reordered view=" + IdToString(view_2_2) + " relative=" +
948 IdToString(view_2_3) + " direction=below",
949 SingleChangeToDescription(*changes1()));
950 }
951
952 // view2 is already below view3.
953 EXPECT_FALSE(ReorderView(vm2(), view_2_2, view_2_3, ORDER_DIRECTION_BELOW));
954
955 // view4 & 5 are unknown to connection2_.
956 EXPECT_FALSE(ReorderView(vm2(), view_1_4, view_1_5, ORDER_DIRECTION_ABOVE));
957
958 // view6 & view3 have different parents.
959 EXPECT_FALSE(ReorderView(vm1(), view_2_3, view_2_6, ORDER_DIRECTION_ABOVE));
960
961 // Non-existent view-ids
962 EXPECT_FALSE(ReorderView(vm1(), BuildViewId(connection_id_1(), 27),
963 BuildViewId(connection_id_1(), 28),
964 ORDER_DIRECTION_ABOVE));
965
966 // view7 & view8 are un-parented.
967 EXPECT_FALSE(ReorderView(vm1(), view_2_7, view_2_8, ORDER_DIRECTION_ABOVE));
968 }
969
970 // Verifies DeleteView works.
971 TEST_F(ViewTreeAppTest, DeleteView) {
972 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
973 Id view_1_1 = BuildViewId(connection_id_1(), 1);
974 Id view_2_2 = vm_client2()->CreateView(2);
975 ASSERT_TRUE(view_2_2);
976
977 // Make 2 a child of 1.
978 {
979 changes1()->clear();
980 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
981 vm_client1_->WaitForChangeCount(1);
982 EXPECT_EQ("HierarchyChanged view=" + IdToString(view_2_2) + " new_parent=" +
983 IdToString(view_1_1) + " old_parent=null",
984 SingleChangeToDescription(*changes1()));
985 }
986
987 // Delete 2.
988 {
989 changes1()->clear();
990 changes2()->clear();
991 ASSERT_TRUE(DeleteView(vm2(), view_2_2));
992 EXPECT_TRUE(changes2()->empty());
993
994 vm_client1_->WaitForChangeCount(1);
995 EXPECT_EQ("ViewDeleted view=" + IdToString(view_2_2),
996 SingleChangeToDescription(*changes1()));
997 }
998 }
999
1000 // Verifies DeleteView isn't allowed from a separate connection.
1001 TEST_F(ViewTreeAppTest, DeleteViewFromAnotherConnectionDisallowed) {
1002 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1003 EXPECT_FALSE(DeleteView(vm2(), BuildViewId(connection_id_1(), 1)));
1004 }
1005
1006 // Verifies if a view was deleted and then reused that other clients are
1007 // properly notified.
1008 TEST_F(ViewTreeAppTest, ReuseDeletedViewId) {
1009 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1010 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1011 Id view_2_2 = vm_client2()->CreateView(2);
1012 ASSERT_TRUE(view_2_2);
1013
1014 // Add 2 to 1.
1015 {
1016 changes1()->clear();
1017 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1018 vm_client1_->WaitForChangeCount(1);
1019 EXPECT_EQ("HierarchyChanged view=" + IdToString(view_2_2) + " new_parent=" +
1020 IdToString(view_1_1) + " old_parent=null",
1021 SingleChangeToDescription(*changes1()));
1022 EXPECT_EQ("[" + ViewParentToString(view_2_2, view_1_1) + "]",
1023 ChangeViewDescription(*changes1()));
1024 }
1025
1026 // Delete 2.
1027 {
1028 changes1()->clear();
1029 ASSERT_TRUE(DeleteView(vm2(), view_2_2));
1030
1031 vm_client1_->WaitForChangeCount(1);
1032 EXPECT_EQ("ViewDeleted view=" + IdToString(view_2_2),
1033 SingleChangeToDescription(*changes1()));
1034 }
1035
1036 // Create 2 again, and add it back to 1. Should get the same notification.
1037 view_2_2 = vm_client2()->CreateView(2);
1038 ASSERT_TRUE(view_2_2);
1039 {
1040 changes1()->clear();
1041 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1042
1043 vm_client1_->WaitForChangeCount(1);
1044 EXPECT_EQ("HierarchyChanged view=" + IdToString(view_2_2) + " new_parent=" +
1045 IdToString(view_1_1) + " old_parent=null",
1046 SingleChangeToDescription(*changes1()));
1047 EXPECT_EQ("[" + ViewParentToString(view_2_2, view_1_1) + "]",
1048 ChangeViewDescription(*changes1()));
1049 }
1050 }
1051
1052 // Assertions for GetViewTree.
1053 TEST_F(ViewTreeAppTest, GetViewTree) {
1054 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1055 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1056
1057 // Create 11 in first connection and make it a child of 1.
1058 Id view_1_11 = vm_client1()->CreateView(11);
1059 ASSERT_TRUE(view_1_11);
1060 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1061 ASSERT_TRUE(AddView(vm1(), view_1_1, view_1_11));
1062
1063 // Create two views in second connection, 2 and 3, both children of 1.
1064 Id view_2_2 = vm_client2()->CreateView(2);
1065 Id view_2_3 = vm_client2()->CreateView(3);
1066 ASSERT_TRUE(view_2_2);
1067 ASSERT_TRUE(view_2_3);
1068 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1069 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_3));
1070
1071 // Verifies GetViewTree() on the root. The root connection sees all.
1072 {
1073 std::vector<TestView> views;
1074 GetViewTree(vm1(), root_view_id(), &views);
1075 ASSERT_EQ(5u, views.size());
1076 EXPECT_EQ(ViewParentToString(root_view_id(), kNullParentId),
1077 views[0].ToString());
1078 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()),
1079 views[1].ToString());
1080 EXPECT_EQ(ViewParentToString(view_1_11, view_1_1), views[2].ToString());
1081 EXPECT_EQ(ViewParentToString(view_2_2, view_1_1), views[3].ToString());
1082 EXPECT_EQ(ViewParentToString(view_2_3, view_1_1), views[4].ToString());
1083 }
1084
1085 // Verifies GetViewTree() on the view 1,1 from vm2(). vm2() sees 1,1 as 1,1
1086 // is vm2()'s root and vm2() sees all the views it created.
1087 {
1088 std::vector<TestView> views;
1089 GetViewTree(vm2(), view_1_1, &views);
1090 ASSERT_EQ(3u, views.size());
1091 EXPECT_EQ(ViewParentToString(view_1_1, kNullParentId), views[0].ToString());
1092 EXPECT_EQ(ViewParentToString(view_2_2, view_1_1), views[1].ToString());
1093 EXPECT_EQ(ViewParentToString(view_2_3, view_1_1), views[2].ToString());
1094 }
1095
1096 // Connection 2 shouldn't be able to get the root tree.
1097 {
1098 std::vector<TestView> views;
1099 GetViewTree(vm2(), root_view_id(), &views);
1100 ASSERT_EQ(0u, views.size());
1101 }
1102 }
1103
1104 TEST_F(ViewTreeAppTest, SetViewBounds) {
1105 Id view_1_1 = vm_client1()->CreateView(1);
1106 ASSERT_TRUE(view_1_1);
1107 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1108
1109 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1110
1111 changes2()->clear();
1112 ASSERT_TRUE(SetViewBounds(vm1(), view_1_1, 0, 0, 100, 100));
1113
1114 vm_client2_->WaitForChangeCount(1);
1115 EXPECT_EQ("BoundsChanged view=" + IdToString(view_1_1) +
1116 " old_bounds=0,0 0x0 new_bounds=0,0 100x100",
1117 SingleChangeToDescription(*changes2()));
1118
1119 // Should not be possible to change the bounds of a view created by another
1120 // connection.
1121 ASSERT_FALSE(SetViewBounds(vm2(), view_1_1, 0, 0, 0, 0));
1122 }
1123
1124 // Verify AddView fails when trying to manipulate views in other roots.
1125 TEST_F(ViewTreeAppTest, CantMoveViewsFromOtherRoot) {
1126 // Create 1 and 2 in the first connection.
1127 Id view_1_1 = vm_client1()->CreateView(1);
1128 Id view_1_2 = vm_client1()->CreateView(2);
1129 ASSERT_TRUE(view_1_1);
1130 ASSERT_TRUE(view_1_2);
1131
1132 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1133
1134 // Try to move 2 to be a child of 1 from connection 2. This should fail as 2
1135 // should not be able to access 1.
1136 ASSERT_FALSE(AddView(vm2(), view_1_1, view_1_2));
1137
1138 // Try to reparent 1 to the root. A connection is not allowed to reparent its
1139 // roots.
1140 ASSERT_FALSE(AddView(vm2(), root_view_id(), view_1_1));
1141 }
1142
1143 // Verify RemoveViewFromParent fails for views that are descendants of the
1144 // roots.
1145 TEST_F(ViewTreeAppTest, CantRemoveViewsInOtherRoots) {
1146 // Create 1 and 2 in the first connection and parent both to the root.
1147 Id view_1_1 = vm_client1()->CreateView(1);
1148 Id view_1_2 = vm_client1()->CreateView(2);
1149 ASSERT_TRUE(view_1_1);
1150 ASSERT_TRUE(view_1_2);
1151
1152 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1153 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_2));
1154
1155 // Establish the second connection and give it the root 1.
1156 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1157
1158 // Connection 2 should not be able to remove view 2 or 1 from its parent.
1159 ASSERT_FALSE(RemoveViewFromParent(vm2(), view_1_2));
1160 ASSERT_FALSE(RemoveViewFromParent(vm2(), view_1_1));
1161
1162 // Create views 10 and 11 in 2.
1163 Id view_2_10 = vm_client2()->CreateView(10);
1164 Id view_2_11 = vm_client2()->CreateView(11);
1165 ASSERT_TRUE(view_2_10);
1166 ASSERT_TRUE(view_2_11);
1167
1168 // Parent 11 to 10.
1169 ASSERT_TRUE(AddView(vm2(), view_2_10, view_2_11));
1170 // Remove 11 from 10.
1171 ASSERT_TRUE(RemoveViewFromParent(vm2(), view_2_11));
1172
1173 // Verify nothing was actually removed.
1174 {
1175 std::vector<TestView> views;
1176 GetViewTree(vm1(), root_view_id(), &views);
1177 ASSERT_EQ(3u, views.size());
1178 EXPECT_EQ(ViewParentToString(root_view_id(), kNullParentId),
1179 views[0].ToString());
1180 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()),
1181 views[1].ToString());
1182 EXPECT_EQ(ViewParentToString(view_1_2, root_view_id()),
1183 views[2].ToString());
1184 }
1185 }
1186
1187 // Verify GetViewTree fails for views that are not descendants of the roots.
1188 TEST_F(ViewTreeAppTest, CantGetViewTreeOfOtherRoots) {
1189 // Create 1 and 2 in the first connection and parent both to the root.
1190 Id view_1_1 = vm_client1()->CreateView(1);
1191 Id view_1_2 = vm_client1()->CreateView(2);
1192 ASSERT_TRUE(view_1_1);
1193 ASSERT_TRUE(view_1_2);
1194
1195 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1196 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_2));
1197
1198 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1199
1200 std::vector<TestView> views;
1201
1202 // Should get nothing for the root.
1203 GetViewTree(vm2(), root_view_id(), &views);
1204 ASSERT_TRUE(views.empty());
1205
1206 // Should get nothing for view 2.
1207 GetViewTree(vm2(), view_1_2, &views);
1208 ASSERT_TRUE(views.empty());
1209
1210 // Should get view 1 if asked for.
1211 GetViewTree(vm2(), view_1_1, &views);
1212 ASSERT_EQ(1u, views.size());
1213 EXPECT_EQ(ViewParentToString(view_1_1, kNullParentId), views[0].ToString());
1214 }
1215
1216 TEST_F(ViewTreeAppTest, EmbedWithSameViewId) {
1217 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1218 changes2()->clear();
1219
1220 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1221 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm1(), view_1_1));
1222
1223 // Connection2 should have been told of the unembed and delete.
1224 {
1225 vm_client2_->WaitForChangeCount(2);
1226 EXPECT_EQ("OnUnembed", ChangesToDescription1(*changes2())[0]);
1227 EXPECT_EQ("ViewDeleted view=" + IdToString(view_1_1),
1228 ChangesToDescription1(*changes2())[1]);
1229 }
1230
1231 // Connection2 has no root. Verify it can't see view 1,1 anymore.
1232 {
1233 std::vector<TestView> views;
1234 GetViewTree(vm2(), view_1_1, &views);
1235 EXPECT_TRUE(views.empty());
1236 }
1237 }
1238
1239 TEST_F(ViewTreeAppTest, EmbedWithSameViewId2) {
1240 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1241 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1242 changes2()->clear();
1243
1244 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm1(), view_1_1));
1245
1246 // Connection2 should have been told about the unembed and delete.
1247 vm_client2_->WaitForChangeCount(2);
1248 changes2()->clear();
1249
1250 // Create a view in the third connection and parent it to the root.
1251 Id view_3_1 = vm_client3()->CreateView(1);
1252 ASSERT_TRUE(view_3_1);
1253 ASSERT_TRUE(AddView(vm3(), view_1_1, view_3_1));
1254
1255 // Connection 1 should have been told about the add (it owns the view).
1256 {
1257 vm_client1_->WaitForChangeCount(1);
1258 EXPECT_EQ("HierarchyChanged view=" + IdToString(view_3_1) + " new_parent=" +
1259 IdToString(view_1_1) + " old_parent=null",
1260 SingleChangeToDescription(*changes1()));
1261 }
1262
1263 // Embed 1,1 again.
1264 {
1265 changes3()->clear();
1266
1267 // We should get a new connection for the new embedding.
1268 scoped_ptr<ViewTreeClientImpl> connection4(
1269 EstablishConnectionViaEmbed(vm1(), view_1_1, nullptr));
1270 ASSERT_TRUE(connection4.get());
1271 EXPECT_EQ("[" + ViewParentToString(view_1_1, kNullParentId) + "]",
1272 ChangeViewDescription(*connection4->tracker()->changes()));
1273
1274 // And 3 should get an unembed and delete.
1275 vm_client3_->WaitForChangeCount(2);
1276 EXPECT_EQ("OnUnembed", ChangesToDescription1(*changes3())[0]);
1277 EXPECT_EQ("ViewDeleted view=" + IdToString(view_1_1),
1278 ChangesToDescription1(*changes3())[1]);
1279 }
1280
1281 // vm3() has no root. Verify it can't see view 1,1 anymore.
1282 {
1283 std::vector<TestView> views;
1284 GetViewTree(vm3(), view_1_1, &views);
1285 EXPECT_TRUE(views.empty());
1286 }
1287
1288 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as
1289 // vm3() can no longer see 1,1.
1290 {
1291 std::vector<TestView> views;
1292 GetViewTree(vm1(), view_1_1, &views);
1293 ASSERT_EQ(1u, views.size());
1294 EXPECT_EQ(ViewParentToString(view_1_1, kNullParentId), views[0].ToString());
1295 }
1296
1297 // Verify vm3() can still see the view it created 3,1.
1298 {
1299 std::vector<TestView> views;
1300 GetViewTree(vm3(), view_3_1, &views);
1301 ASSERT_EQ(1u, views.size());
1302 EXPECT_EQ(ViewParentToString(view_3_1, kNullParentId), views[0].ToString());
1303 }
1304 }
1305
1306 // Assertions for SetViewVisibility.
1307 TEST_F(ViewTreeAppTest, SetViewVisibility) {
1308 // Create 1 and 2 in the first connection and parent both to the root.
1309 Id view_1_1 = vm_client1()->CreateView(1);
1310 Id view_1_2 = vm_client1()->CreateView(2);
1311 ASSERT_TRUE(view_1_1);
1312 ASSERT_TRUE(view_1_2);
1313
1314 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1315 {
1316 std::vector<TestView> views;
1317 GetViewTree(vm1(), root_view_id(), &views);
1318 ASSERT_EQ(2u, views.size());
1319 EXPECT_EQ(ViewParentToString(root_view_id(), kNullParentId) +
1320 " visible=true drawn=true",
1321 views[0].ToString2());
1322 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()) +
1323 " visible=false drawn=false",
1324 views[1].ToString2());
1325 }
1326
1327 // Show all the views.
1328 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, true));
1329 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_2, true));
1330 {
1331 std::vector<TestView> views;
1332 GetViewTree(vm1(), root_view_id(), &views);
1333 ASSERT_EQ(2u, views.size());
1334 EXPECT_EQ(ViewParentToString(root_view_id(), kNullParentId) +
1335 " visible=true drawn=true",
1336 views[0].ToString2());
1337 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()) +
1338 " visible=true drawn=true",
1339 views[1].ToString2());
1340 }
1341
1342 // Hide 1.
1343 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, false));
1344 {
1345 std::vector<TestView> views;
1346 GetViewTree(vm1(), view_1_1, &views);
1347 ASSERT_EQ(1u, views.size());
1348 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()) +
1349 " visible=false drawn=false",
1350 views[0].ToString2());
1351 }
1352
1353 // Attach 2 to 1.
1354 ASSERT_TRUE(AddView(vm1(), view_1_1, view_1_2));
1355 {
1356 std::vector<TestView> views;
1357 GetViewTree(vm1(), view_1_1, &views);
1358 ASSERT_EQ(2u, views.size());
1359 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()) +
1360 " visible=false drawn=false",
1361 views[0].ToString2());
1362 EXPECT_EQ(
1363 ViewParentToString(view_1_2, view_1_1) + " visible=true drawn=false",
1364 views[1].ToString2());
1365 }
1366
1367 // Show 1.
1368 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, true));
1369 {
1370 std::vector<TestView> views;
1371 GetViewTree(vm1(), view_1_1, &views);
1372 ASSERT_EQ(2u, views.size());
1373 EXPECT_EQ(ViewParentToString(view_1_1, root_view_id()) +
1374 " visible=true drawn=true",
1375 views[0].ToString2());
1376 EXPECT_EQ(
1377 ViewParentToString(view_1_2, view_1_1) + " visible=true drawn=true",
1378 views[1].ToString2());
1379 }
1380 }
1381
1382 // Assertions for SetViewVisibility sending notifications.
1383 TEST_F(ViewTreeAppTest, SetViewVisibilityNotifications) {
1384 // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root.
1385 Id view_1_1 = vm_client1()->CreateView(1);
1386 ASSERT_TRUE(view_1_1);
1387 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, true));
1388 Id view_1_2 = vm_client1()->CreateView(2);
1389 ASSERT_TRUE(view_1_2);
1390 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_2, true));
1391 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1392 ASSERT_TRUE(AddView(vm1(), view_1_1, view_1_2));
1393
1394 // Establish the second connection at 1,2.
1395 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnectionWithRoot(view_1_2));
1396
1397 // Add 2,3 as a child of 1,2.
1398 Id view_2_3 = vm_client2()->CreateView(3);
1399 ASSERT_TRUE(view_2_3);
1400 ASSERT_TRUE(SetViewVisibility(vm2(), view_2_3, true));
1401 ASSERT_TRUE(AddView(vm2(), view_1_2, view_2_3));
1402 WaitForAllMessages(vm1());
1403
1404 changes2()->clear();
1405 // Hide 1,2 from connection 1. Connection 2 should see this.
1406 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_2, false));
1407 {
1408 vm_client2_->WaitForChangeCount(1);
1409 EXPECT_EQ(
1410 "VisibilityChanged view=" + IdToString(view_1_2) + " visible=false",
1411 SingleChangeToDescription(*changes2()));
1412 }
1413
1414 changes1()->clear();
1415 // Show 1,2 from connection 2, connection 1 should be notified.
1416 ASSERT_TRUE(SetViewVisibility(vm2(), view_1_2, true));
1417 {
1418 vm_client1_->WaitForChangeCount(1);
1419 EXPECT_EQ(
1420 "VisibilityChanged view=" + IdToString(view_1_2) + " visible=true",
1421 SingleChangeToDescription(*changes1()));
1422 }
1423
1424 changes2()->clear();
1425 // Hide 1,1, connection 2 should be told the draw state changed.
1426 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, false));
1427 {
1428 vm_client2_->WaitForChangeCount(1);
1429 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_2) + " drawn=false",
1430 SingleChangeToDescription(*changes2()));
1431 }
1432
1433 changes2()->clear();
1434 // Show 1,1 from connection 1. Connection 2 should see this.
1435 ASSERT_TRUE(SetViewVisibility(vm1(), view_1_1, true));
1436 {
1437 vm_client2_->WaitForChangeCount(1);
1438 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_2) + " drawn=true",
1439 SingleChangeToDescription(*changes2()));
1440 }
1441
1442 // Change visibility of 2,3, connection 1 should see this.
1443 changes1()->clear();
1444 ASSERT_TRUE(SetViewVisibility(vm2(), view_2_3, false));
1445 {
1446 vm_client1_->WaitForChangeCount(1);
1447 EXPECT_EQ(
1448 "VisibilityChanged view=" + IdToString(view_2_3) + " visible=false",
1449 SingleChangeToDescription(*changes1()));
1450 }
1451
1452 changes2()->clear();
1453 // Remove 1,1 from the root, connection 2 should see drawn state changed.
1454 ASSERT_TRUE(RemoveViewFromParent(vm1(), view_1_1));
1455 {
1456 vm_client2_->WaitForChangeCount(1);
1457 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_2) + " drawn=false",
1458 SingleChangeToDescription(*changes2()));
1459 }
1460
1461 changes2()->clear();
1462 // Add 1,1 back to the root, connection 2 should see drawn state changed.
1463 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1464 {
1465 vm_client2_->WaitForChangeCount(1);
1466 EXPECT_EQ("DrawnStateChanged view=" + IdToString(view_1_2) + " drawn=true",
1467 SingleChangeToDescription(*changes2()));
1468 }
1469 }
1470
1471 TEST_F(ViewTreeAppTest, SetViewProperty) {
1472 Id view_1_1 = vm_client1()->CreateView(1);
1473 ASSERT_TRUE(view_1_1);
1474
1475 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1476 changes2()->clear();
1477
1478 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1479 {
1480 std::vector<TestView> views;
1481 GetViewTree(vm1(), root_view_id(), &views);
1482 ASSERT_EQ(2u, views.size());
1483 EXPECT_EQ(root_view_id(), views[0].view_id);
1484 EXPECT_EQ(view_1_1, views[1].view_id);
1485 ASSERT_EQ(0u, views[1].properties.size());
1486 }
1487
1488 // Set properties on 1.
1489 changes2()->clear();
1490 std::vector<uint8_t> one(1, '1');
1491 ASSERT_TRUE(SetViewProperty(vm1(), view_1_1, "one", &one));
1492 {
1493 vm_client2_->WaitForChangeCount(1);
1494 EXPECT_EQ(
1495 "PropertyChanged view=" + IdToString(view_1_1) + " key=one value=1",
1496 SingleChangeToDescription(*changes2()));
1497 }
1498
1499 // Test that our properties exist in the view tree
1500 {
1501 std::vector<TestView> views;
1502 GetViewTree(vm1(), view_1_1, &views);
1503 ASSERT_EQ(1u, views.size());
1504 ASSERT_EQ(1u, views[0].properties.size());
1505 EXPECT_EQ(one, views[0].properties["one"]);
1506 }
1507
1508 changes2()->clear();
1509 // Set back to null.
1510 ASSERT_TRUE(SetViewProperty(vm1(), view_1_1, "one", NULL));
1511 {
1512 vm_client2_->WaitForChangeCount(1);
1513 EXPECT_EQ(
1514 "PropertyChanged view=" + IdToString(view_1_1) + " key=one value=NULL",
1515 SingleChangeToDescription(*changes2()));
1516 }
1517 }
1518
1519 TEST_F(ViewTreeAppTest, OnEmbeddedAppDisconnected) {
1520 // Create connection 2 and 3.
1521 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1522 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1523 Id view_2_2 = vm_client2()->CreateView(2);
1524 ASSERT_TRUE(view_2_2);
1525 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1526 changes2()->clear();
1527 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), view_2_2));
1528
1529 // Connection 1 should get a hierarchy change for view_2_2.
1530 vm_client1_->WaitForChangeCount(1);
1531 changes1()->clear();
1532
1533 // Close connection 3. Connection 2 (which had previously embedded 3) should
1534 // be notified of this.
1535 vm_client3_.reset();
1536 vm_client2_->WaitForChangeCount(1);
1537 EXPECT_EQ("OnEmbeddedAppDisconnected view=" + IdToString(view_2_2),
1538 SingleChangeToDescription(*changes2()));
1539
1540 vm_client1_->WaitForChangeCount(1);
1541 EXPECT_EQ("OnEmbeddedAppDisconnected view=" + IdToString(view_2_2),
1542 SingleChangeToDescription(*changes1()));
1543 }
1544
1545 // Verifies when the parent of an Embed() is destroyed the embedded app gets
1546 // a ViewDeleted (and doesn't trigger a DCHECK).
1547 TEST_F(ViewTreeAppTest, OnParentOfEmbedDisconnects) {
1548 // Create connection 2 and 3.
1549 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1550 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1551 ASSERT_TRUE(AddView(vm1(), root_view_id(), view_1_1));
1552 Id view_2_2 = vm_client2()->CreateView(2);
1553 Id view_2_3 = vm_client2()->CreateView(3);
1554 ASSERT_TRUE(view_2_2);
1555 ASSERT_TRUE(view_2_3);
1556 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1557 ASSERT_TRUE(AddView(vm2(), view_2_2, view_2_3));
1558 changes2()->clear();
1559 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), view_2_3));
1560 changes3()->clear();
1561
1562 // Close connection 2. Connection 3 should get a delete (for its root).
1563 vm_client2_.reset();
1564 vm_client3_->WaitForChangeCount(1);
1565 EXPECT_EQ("ViewDeleted view=" + IdToString(view_2_3),
1566 SingleChangeToDescription(*changes3()));
1567 }
1568
1569 // Verifies ViewTreeImpl doesn't incorrectly erase from its internal
1570 // map when a view from another connection with the same view_id is removed.
1571 TEST_F(ViewTreeAppTest, DontCleanMapOnDestroy) {
1572 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1573 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1574 ASSERT_TRUE(vm_client2()->CreateView(1));
1575 changes1()->clear();
1576 vm_client2_.reset();
1577 vm_client1_->WaitForChangeCount(1);
1578 EXPECT_EQ("OnEmbeddedAppDisconnected view=" + IdToString(view_1_1),
1579 SingleChangeToDescription(*changes1()));
1580 std::vector<TestView> views;
1581 GetViewTree(vm1(), view_1_1, &views);
1582 EXPECT_FALSE(views.empty());
1583 }
1584
1585 // Verifies Embed() works when supplying a ViewTreeClient.
1586 TEST_F(ViewTreeAppTest, EmbedSupplyingViewTreeClient) {
1587 ASSERT_TRUE(vm_client1()->CreateView(1));
1588
1589 ViewTreeClientImpl client2(application_impl());
1590 mojo::ViewTreeClientPtr client2_ptr;
1591 mojo::Binding<ViewTreeClient> client2_binding(&client2, &client2_ptr);
1592 ASSERT_TRUE(
1593 Embed(vm1(), BuildViewId(connection_id_1(), 1), client2_ptr.Pass()));
1594 client2.WaitForOnEmbed();
1595 EXPECT_EQ("OnEmbed",
1596 SingleChangeToDescription(*client2.tracker()->changes()));
1597 }
1598
1599 TEST_F(ViewTreeAppTest, EmbedFailsFromOtherConnection) {
1600 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1601
1602 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1603 Id view_2_2 = vm_client2()->CreateView(2);
1604 ASSERT_TRUE(view_2_2);
1605 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1606 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), view_2_2));
1607
1608 Id view_3_3 = vm_client3()->CreateView(3);
1609 ASSERT_TRUE(view_3_3);
1610 ASSERT_TRUE(AddView(vm3(), view_2_2, view_3_3));
1611
1612 // 2 should not be able to embed in view_3_3 as view_3_3 was not created by
1613 // 2.
1614 EXPECT_FALSE(EmbedUrl(application_impl(), vm2(), application_impl()->url(),
1615 view_3_3));
1616 }
1617
1618 // Verifies Embed() from window manager on another connections view works.
1619 TEST_F(ViewTreeAppTest, EmbedFromOtherConnection) {
1620 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1621
1622 Id view_1_1 = BuildViewId(connection_id_1(), 1);
1623 Id view_2_2 = vm_client2()->CreateView(2);
1624 ASSERT_TRUE(view_2_2);
1625 ASSERT_TRUE(AddView(vm2(), view_1_1, view_2_2));
1626
1627 changes2()->clear();
1628
1629 // Establish a third connection in view_2_2.
1630 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm1(), view_2_2));
1631
1632 WaitForAllMessages(vm2());
1633 EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2()));
1634 }
1635
1636 TEST_F(ViewTreeAppTest, CantEmbedFromConnectionRoot) {
1637 // Shouldn't be able to embed into the root.
1638 ASSERT_FALSE(EmbedUrl(application_impl(), vm1(), application_impl()->url(),
1639 root_view_id()));
1640
1641 // Even though the call above failed a ViewTreeClient was obtained. We need to
1642 // wait for it else we throw off the next connect.
1643 WaitForViewTreeClient();
1644
1645 // Don't allow a connection to embed into its own root.
1646 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1647 EXPECT_FALSE(EmbedUrl(application_impl(), vm2(), application_impl()->url(),
1648 BuildViewId(connection_id_1(), 1)));
1649
1650 // Need to wait for a ViewTreeClient for same reason as above.
1651 WaitForViewTreeClient();
1652
1653 Id view_1_2 = vm_client1()->CreateView(2);
1654 ASSERT_TRUE(view_1_2);
1655 ASSERT_TRUE(AddView(vm1(), BuildViewId(connection_id_1(), 1), view_1_2));
1656 vm1()->SetAccessPolicy(view_1_2, ViewTree::ACCESS_POLICY_EMBED_ROOT);
1657 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm1(), view_1_2));
1658
1659 // view_1_2 is vm3's root, so even though v3 is an embed root it should not
1660 // be able to Embed into itself.
1661 ASSERT_FALSE(EmbedUrl(application_impl(), vm3(), application_impl()->url(),
1662 view_1_2));
1663 }
1664
1665 // TODO(sky): need to better track changes to initial connection. For example,
1666 // that SetBounsdViews/AddView and the like don't result in messages to the
1667 // originating connection.
1668
1669 // TODO(sky): make sure coverage of what was
1670 // ViewManagerTest.SecondEmbedRoot_InitService and
1671 // ViewManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window manager
1672 // tests.
1673
1674 } // namespace view_manager
OLDNEW
« no previous file with comments | « components/view_manager/view_manager_client_apptest.cc ('k') | components/view_manager/view_tree_host_connection.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698