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