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