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 <string> | |
6 #include <vector> | |
7 | |
8 #include "base/at_exit.h" | |
9 #include "base/auto_reset.h" | |
10 #include "base/bind.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/memory/scoped_vector.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "base/run_loop.h" | |
15 #include "base/strings/stringprintf.h" | |
16 #include "mojo/application_manager/application_manager.h" | |
17 #include "mojo/common/common_type_converters.h" | |
18 #include "mojo/converters/geometry/geometry_type_converters.h" | |
19 #include "mojo/public/cpp/application/application_connection.h" | |
20 #include "mojo/public/cpp/application/application_delegate.h" | |
21 #include "mojo/public/cpp/application/application_impl.h" | |
22 #include "mojo/public/cpp/application/connect.h" | |
23 #include "mojo/public/cpp/application/interface_factory_impl.h" | |
24 #include "mojo/public/cpp/bindings/lib/router.h" | |
25 #include "mojo/public/interfaces/application/service_provider.mojom.h" | |
26 #include "mojo/services/public/cpp/native_viewport/args.h" | |
27 #include "mojo/services/public/cpp/view_manager/types.h" | |
28 #include "mojo/services/public/cpp/view_manager/util.h" | |
29 #include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h" | |
30 #include "mojo/services/public/interfaces/window_manager/window_manager.mojom.h" | |
31 #include "mojo/services/public/interfaces/window_manager/window_manager_internal
.mojom.h" | |
32 #include "mojo/services/view_manager/ids.h" | |
33 #include "mojo/services/view_manager/test_change_tracker.h" | |
34 #include "mojo/shell/shell_test_helper.h" | |
35 #include "testing/gtest/include/gtest/gtest.h" | |
36 #include "ui/gfx/geometry/rect.h" | |
37 | |
38 #if defined(OS_WIN) | |
39 #include "ui/gfx/win/window_impl.h" | |
40 #endif | |
41 | |
42 namespace mojo { | |
43 namespace service { | |
44 | |
45 namespace { | |
46 | |
47 const char kTestServiceURL[] = "mojo:test_url"; | |
48 const char kTestServiceURL2[] = "mojo:test_url2"; | |
49 | |
50 // ViewManagerProxy is a proxy to an ViewManagerService. It handles invoking | |
51 // ViewManagerService functions on the right thread in a synchronous manner | |
52 // (each ViewManagerService cover function blocks until the response from the | |
53 // ViewManagerService is returned). In addition it tracks the set of | |
54 // ViewManagerClient messages received by way of a vector of Changes. Use | |
55 // DoRunLoopUntilChangesCount() to wait for a certain number of messages to be | |
56 // received. | |
57 class ViewManagerProxy : public TestChangeTracker::Delegate { | |
58 public: | |
59 explicit ViewManagerProxy(TestChangeTracker* tracker) | |
60 : tracker_(tracker), | |
61 main_loop_(nullptr), | |
62 view_manager_(nullptr), | |
63 window_manager_client_(nullptr), | |
64 quit_count_(0), | |
65 router_(nullptr) { | |
66 } | |
67 | |
68 ~ViewManagerProxy() override {} | |
69 | |
70 // Returns true if in an initial state. If this returns false it means the | |
71 // last test didn't clean up properly, or most likely didn't invoke | |
72 // WaitForInstance() when it needed to. | |
73 static bool IsInInitialState() { return instance_ == NULL; } | |
74 | |
75 // Runs a message loop until the single instance has been created. | |
76 static ViewManagerProxy* WaitForInstance() { | |
77 if (!instance_ || !instance_->view_manager()) | |
78 RunMainLoop(); | |
79 ViewManagerProxy* instance = instance_; | |
80 instance_ = NULL; | |
81 return instance; | |
82 } | |
83 | |
84 ViewManagerService* view_manager() { return view_manager_; } | |
85 WindowManagerInternalClient* window_manager_client() { | |
86 return window_manager_client_; | |
87 } | |
88 | |
89 // Runs the main loop until |count| changes have been received. | |
90 std::vector<Change> DoRunLoopUntilChangesCount(size_t count) { | |
91 DCHECK_EQ(0u, quit_count_); | |
92 if (tracker_->changes()->size() >= count) { | |
93 CopyChangesFromTracker(); | |
94 return changes_; | |
95 } | |
96 quit_count_ = count - tracker_->changes()->size(); | |
97 // Run the current message loop. When |count| Changes have been received, | |
98 // we'll quit. | |
99 RunMainLoop(); | |
100 return changes_; | |
101 } | |
102 | |
103 const std::vector<Change>& changes() const { return changes_; } | |
104 | |
105 // Destroys the connection, blocking until done. | |
106 void Destroy() { | |
107 router_->CloseMessagePipe(); | |
108 } | |
109 | |
110 void ClearChanges() { | |
111 changes_.clear(); | |
112 tracker_->changes()->clear(); | |
113 } | |
114 | |
115 void CopyChangesFromTracker() { | |
116 std::vector<Change> changes; | |
117 tracker_->changes()->swap(changes); | |
118 changes_.swap(changes); | |
119 } | |
120 | |
121 // The following functions are cover methods for ViewManagerService. They | |
122 // block until the result is received. | |
123 bool CreateView(Id view_id) { | |
124 changes_.clear(); | |
125 ErrorCode result = ERROR_CODE_NONE; | |
126 view_manager_->CreateView( | |
127 view_id, | |
128 base::Bind(&ViewManagerProxy::GotResultWithErrorCode, | |
129 base::Unretained(this), | |
130 &result)); | |
131 RunMainLoop(); | |
132 return result == ERROR_CODE_NONE; | |
133 } | |
134 ErrorCode CreateViewWithErrorCode(Id view_id) { | |
135 changes_.clear(); | |
136 ErrorCode result = ERROR_CODE_NONE; | |
137 view_manager_->CreateView( | |
138 view_id, | |
139 base::Bind(&ViewManagerProxy::GotResultWithErrorCode, | |
140 base::Unretained(this), | |
141 &result)); | |
142 RunMainLoop(); | |
143 return result; | |
144 } | |
145 bool AddView(Id parent, Id child) { | |
146 changes_.clear(); | |
147 bool result = false; | |
148 view_manager_->AddView(parent, child, | |
149 base::Bind(&ViewManagerProxy::GotResult, | |
150 base::Unretained(this), &result)); | |
151 RunMainLoop(); | |
152 return result; | |
153 } | |
154 bool RemoveViewFromParent(Id view_id) { | |
155 changes_.clear(); | |
156 bool result = false; | |
157 view_manager_->RemoveViewFromParent( | |
158 view_id, | |
159 base::Bind( | |
160 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
161 RunMainLoop(); | |
162 return result; | |
163 } | |
164 bool ReorderView(Id view_id, Id relative_view_id, OrderDirection direction) { | |
165 changes_.clear(); | |
166 bool result = false; | |
167 view_manager_->ReorderView( | |
168 view_id, | |
169 relative_view_id, | |
170 direction, | |
171 base::Bind( | |
172 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
173 RunMainLoop(); | |
174 return result; | |
175 } | |
176 void GetViewTree(Id view_id, std::vector<TestView>* views) { | |
177 changes_.clear(); | |
178 view_manager_->GetViewTree( | |
179 view_id, | |
180 base::Bind( | |
181 &ViewManagerProxy::GotViewTree, base::Unretained(this), views)); | |
182 RunMainLoop(); | |
183 } | |
184 bool Embed(const Id view_id, const char* url) { | |
185 changes_.clear(); | |
186 base::AutoReset<bool> auto_reset(&in_embed_, true); | |
187 bool result = false; | |
188 ServiceProviderPtr services; | |
189 view_manager_->Embed( | |
190 url, | |
191 view_id, | |
192 MakeRequest<ServiceProvider>(services.PassMessagePipe()), | |
193 base::Bind( | |
194 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
195 RunMainLoop(); | |
196 return result; | |
197 } | |
198 bool DeleteView(Id view_id) { | |
199 changes_.clear(); | |
200 bool result = false; | |
201 view_manager_->DeleteView( | |
202 view_id, | |
203 base::Bind( | |
204 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
205 RunMainLoop(); | |
206 return result; | |
207 } | |
208 bool SetViewBounds(Id view_id, const gfx::Rect& bounds) { | |
209 changes_.clear(); | |
210 bool result = false; | |
211 view_manager_->SetViewBounds( | |
212 view_id, | |
213 Rect::From(bounds), | |
214 base::Bind( | |
215 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
216 RunMainLoop(); | |
217 return result; | |
218 } | |
219 bool SetViewVisibility(Id view_id, bool visible) { | |
220 changes_.clear(); | |
221 bool result = false; | |
222 view_manager_->SetViewVisibility( | |
223 view_id, | |
224 visible, | |
225 base::Bind( | |
226 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
227 RunMainLoop(); | |
228 return result; | |
229 } | |
230 bool SetViewProperty(Id view_id, const std::string& name, | |
231 const std::vector<uint8_t>* data) { | |
232 changes_.clear(); | |
233 bool result = false; | |
234 Array<uint8_t> mojo_data; | |
235 if (data) | |
236 mojo_data = Array<uint8_t>::From(*data); | |
237 view_manager_->SetViewProperty( | |
238 view_id, | |
239 name, | |
240 mojo_data.Pass(), | |
241 base::Bind( | |
242 &ViewManagerProxy::GotResult, base::Unretained(this), &result)); | |
243 RunMainLoop(); | |
244 return result; | |
245 } | |
246 | |
247 void set_view_manager(ViewManagerService* view_manager) { | |
248 view_manager_ = view_manager; | |
249 SetInstance(this); | |
250 } | |
251 | |
252 private: | |
253 friend class TestViewManagerClientConnection; | |
254 friend class TestWindowManagerImpl; | |
255 | |
256 void set_router(mojo::internal::Router* router) { router_ = router; } | |
257 | |
258 void set_window_manager_client(WindowManagerInternalClient* client) { | |
259 window_manager_client_ = client; | |
260 } | |
261 | |
262 static void RunMainLoop() { | |
263 DCHECK(!main_run_loop_); | |
264 main_run_loop_ = new base::RunLoop; | |
265 main_run_loop_->Run(); | |
266 delete main_run_loop_; | |
267 main_run_loop_ = NULL; | |
268 } | |
269 | |
270 void QuitCountReached() { | |
271 CopyChangesFromTracker(); | |
272 main_run_loop_->Quit(); | |
273 } | |
274 | |
275 static void SetInstance(ViewManagerProxy* instance) { | |
276 DCHECK(!instance_); | |
277 instance_ = instance; | |
278 // Embed() runs its own run loop that is quit when the result is | |
279 // received. Embed() also results in a new instance. If we quit here while | |
280 // waiting for a Embed() we would prematurely return before we got the | |
281 // result from Embed(). | |
282 if (!in_embed_ && main_run_loop_) | |
283 main_run_loop_->Quit(); | |
284 } | |
285 | |
286 // Callbacks from the various ViewManagerService functions. | |
287 void GotResult(bool* result_cache, bool result) { | |
288 *result_cache = result; | |
289 DCHECK(main_run_loop_); | |
290 main_run_loop_->Quit(); | |
291 } | |
292 | |
293 void GotResultWithErrorCode(ErrorCode* error_code_cache, | |
294 ErrorCode error_code) { | |
295 *error_code_cache = error_code; | |
296 DCHECK(main_run_loop_); | |
297 main_run_loop_->Quit(); | |
298 } | |
299 | |
300 void GotViewTree(std::vector<TestView>* views, Array<ViewDataPtr> results) { | |
301 ViewDatasToTestViews(results, views); | |
302 DCHECK(main_run_loop_); | |
303 main_run_loop_->Quit(); | |
304 } | |
305 | |
306 // TestChangeTracker::Delegate: | |
307 void OnChangeAdded() override { | |
308 if (quit_count_ > 0 && --quit_count_ == 0) | |
309 QuitCountReached(); | |
310 } | |
311 | |
312 static ViewManagerProxy* instance_; | |
313 static base::RunLoop* main_run_loop_; | |
314 static bool in_embed_; | |
315 | |
316 TestChangeTracker* tracker_; | |
317 | |
318 // MessageLoop of the test. | |
319 base::MessageLoop* main_loop_; | |
320 | |
321 ViewManagerService* view_manager_; | |
322 WindowManagerInternalClient* window_manager_client_; | |
323 | |
324 // Number of changes we're waiting on until we quit the current loop. | |
325 size_t quit_count_; | |
326 | |
327 std::vector<Change> changes_; | |
328 | |
329 mojo::internal::Router* router_; | |
330 | |
331 DISALLOW_COPY_AND_ASSIGN(ViewManagerProxy); | |
332 }; | |
333 | |
334 // static | |
335 ViewManagerProxy* ViewManagerProxy::instance_ = NULL; | |
336 | |
337 // static | |
338 base::RunLoop* ViewManagerProxy::main_run_loop_ = NULL; | |
339 | |
340 // static | |
341 bool ViewManagerProxy::in_embed_ = false; | |
342 | |
343 class TestViewManagerClientConnection | |
344 : public InterfaceImpl<ViewManagerClient> { | |
345 public: | |
346 TestViewManagerClientConnection() : proxy_(&tracker_) { | |
347 tracker_.set_delegate(&proxy_); | |
348 } | |
349 | |
350 TestChangeTracker* tracker() { return &tracker_; } | |
351 | |
352 ViewManagerProxy* proxy() { return &proxy_; } | |
353 | |
354 void OnConnectionEstablished() { | |
355 proxy_.set_router(internal_router()); | |
356 proxy_.set_view_manager(client()); | |
357 } | |
358 | |
359 // ViewManagerClient: | |
360 void OnEmbed(ConnectionSpecificId connection_id, | |
361 const String& creator_url, | |
362 ViewDataPtr root, | |
363 InterfaceRequest<ServiceProvider> services, | |
364 ScopedMessagePipeHandle window_manager_pipe) override { | |
365 tracker()->OnEmbed(connection_id, creator_url, root.Pass()); | |
366 } | |
367 void OnEmbeddedAppDisconnected(Id view_id) override { | |
368 // Coverage of this is in view_manager_server_apptest. | |
369 } | |
370 void OnViewBoundsChanged(Id view_id, | |
371 RectPtr old_bounds, | |
372 RectPtr new_bounds) override { | |
373 tracker()->OnViewBoundsChanged( | |
374 view_id, old_bounds.Pass(), new_bounds.Pass()); | |
375 } | |
376 void OnViewHierarchyChanged(Id view, | |
377 Id new_parent, | |
378 Id old_parent, | |
379 Array<ViewDataPtr> views) override { | |
380 tracker()->OnViewHierarchyChanged( | |
381 view, new_parent, old_parent, views.Pass()); | |
382 } | |
383 void OnViewReordered(Id view_id, | |
384 Id relative_view_id, | |
385 OrderDirection direction) override { | |
386 tracker()->OnViewReordered(view_id, relative_view_id, direction); | |
387 } | |
388 void OnViewDeleted(Id view) override { tracker()->OnViewDeleted(view); } | |
389 void OnViewVisibilityChanged(uint32_t view, bool visible) override { | |
390 tracker()->OnViewVisibilityChanged(view, visible); | |
391 } | |
392 void OnViewDrawnStateChanged(uint32_t view, bool drawn) override { | |
393 tracker()->OnViewDrawnStateChanged(view, drawn); | |
394 } | |
395 void OnViewInputEvent(Id view_id, | |
396 EventPtr event, | |
397 const Callback<void()>& callback) override { | |
398 tracker()->OnViewInputEvent(view_id, event.Pass()); | |
399 } | |
400 void OnViewSharedPropertyChanged(uint32_t view, | |
401 const String& name, | |
402 Array<uint8_t> new_data) override { | |
403 tracker_.OnViewSharedPropertyChanged(view, name, new_data.Pass()); | |
404 } | |
405 | |
406 private: | |
407 TestChangeTracker tracker_; | |
408 ViewManagerProxy proxy_; | |
409 | |
410 DISALLOW_COPY_AND_ASSIGN(TestViewManagerClientConnection); | |
411 }; | |
412 | |
413 // Used with ViewManagerService::Embed(). Creates a | |
414 // TestViewManagerClientConnection, which creates and owns the ViewManagerProxy. | |
415 class EmbedApplicationLoader : public ApplicationLoader, | |
416 ApplicationDelegate, | |
417 public InterfaceFactory<ViewManagerClient> { | |
418 public: | |
419 EmbedApplicationLoader() {} | |
420 ~EmbedApplicationLoader() override {} | |
421 | |
422 // ApplicationLoader implementation: | |
423 void Load(ApplicationManager* manager, | |
424 const GURL& url, | |
425 ScopedMessagePipeHandle shell_handle, | |
426 LoadCallback callback) override { | |
427 ASSERT_TRUE(shell_handle.is_valid()); | |
428 scoped_ptr<ApplicationImpl> app( | |
429 new ApplicationImpl(this, shell_handle.Pass())); | |
430 apps_.push_back(app.release()); | |
431 } | |
432 void OnApplicationError(ApplicationManager* manager, | |
433 const GURL& url) override {} | |
434 | |
435 // ApplicationDelegate implementation: | |
436 bool ConfigureIncomingConnection(ApplicationConnection* connection) override { | |
437 connection->AddService<ViewManagerClient>(this); | |
438 return true; | |
439 } | |
440 | |
441 // InterfaceFactory<ViewManagerClient> implementation: | |
442 void Create(ApplicationConnection* connection, | |
443 InterfaceRequest<ViewManagerClient> request) override { | |
444 auto client_connection = new TestViewManagerClientConnection; | |
445 BindToRequest(client_connection, &request); | |
446 client_connection->OnConnectionEstablished(); | |
447 } | |
448 | |
449 private: | |
450 ScopedVector<ApplicationImpl> apps_; | |
451 | |
452 DISALLOW_COPY_AND_ASSIGN(EmbedApplicationLoader); | |
453 }; | |
454 | |
455 class TestWindowManagerImpl : public InterfaceImpl<WindowManager> { | |
456 public: | |
457 explicit TestWindowManagerImpl(ApplicationConnection* connection) | |
458 : view_manager_client_(nullptr), got_initial_embed_(false) { | |
459 // WindowManager is expected to establish initial connection to VM. | |
460 ApplicationConnection* view_manager_app = | |
461 connection->ConnectToApplication("mojo:view_manager"); | |
462 view_manager_app->ConnectToService(&view_manager_); | |
463 view_manager_app->ConnectToService(&window_manager_client_); | |
464 | |
465 view_manager_client_ = new TestViewManagerClientConnection(); | |
466 view_manager_.set_client(view_manager_client_); | |
467 view_manager_client_->proxy()->set_window_manager_client( | |
468 window_manager_client_.get()); | |
469 view_manager_client_->proxy()->set_view_manager(view_manager_.get()); | |
470 } | |
471 | |
472 virtual ~TestWindowManagerImpl() {} | |
473 | |
474 TestViewManagerClientConnection* view_manager_client() { | |
475 return view_manager_client_; | |
476 } | |
477 | |
478 // WindowManager: | |
479 void Embed(const String& url, | |
480 InterfaceRequest<ServiceProvider> service_provider) override { | |
481 if (!got_initial_embed_) { | |
482 got_initial_embed_ = true; | |
483 return; | |
484 } | |
485 view_manager_client_->tracker()->DelegateEmbed(url); | |
486 } | |
487 void SetCapture(Id view, const Callback<void(bool)>& callback) override { | |
488 callback.Run(true); | |
489 } | |
490 void FocusWindow(Id view, const Callback<void(bool)>& callback) override { | |
491 callback.Run(true); | |
492 } | |
493 void ActivateWindow(Id view, const Callback<void(bool)>& callback) override { | |
494 callback.Run(true); | |
495 } | |
496 | |
497 private: | |
498 ViewManagerServicePtr view_manager_; | |
499 TestViewManagerClientConnection* view_manager_client_; | |
500 WindowManagerInternalClientPtr window_manager_client_; | |
501 | |
502 // Did we get Embed() yet? | |
503 bool got_initial_embed_; | |
504 | |
505 DISALLOW_COPY_AND_ASSIGN(TestWindowManagerImpl); | |
506 }; | |
507 | |
508 class WindowManagerLoader : public ApplicationLoader, | |
509 public ApplicationDelegate, | |
510 public InterfaceFactory<WindowManager> { | |
511 public: | |
512 explicit WindowManagerLoader(EmbedApplicationLoader* app_loader) | |
513 : app_loader_(app_loader) {} | |
514 virtual ~WindowManagerLoader() {} | |
515 | |
516 // ApplicationLoader implementation: | |
517 virtual void Load(ApplicationManager* manager, | |
518 const GURL& url, | |
519 ScopedMessagePipeHandle shell_handle, | |
520 LoadCallback callback) override { | |
521 ASSERT_TRUE(shell_handle.is_valid()); | |
522 scoped_ptr<ApplicationImpl> app( | |
523 new ApplicationImpl(this, shell_handle.Pass())); | |
524 apps_.push_back(app.release()); | |
525 } | |
526 virtual void OnApplicationError(ApplicationManager* manager, | |
527 const GURL& url) override {} | |
528 | |
529 // ApplicationDelegate implementation: | |
530 virtual bool ConfigureIncomingConnection( | |
531 ApplicationConnection* connection) override { | |
532 connection->AddService<WindowManager>(this); | |
533 return true; | |
534 } | |
535 | |
536 // InterfaceFactory<WindowManagerService>: | |
537 virtual void Create(ApplicationConnection* connection, | |
538 InterfaceRequest<WindowManager> request) override { | |
539 TestWindowManagerImpl* window_manager = | |
540 new TestWindowManagerImpl(connection); | |
541 BindToRequest(window_manager, &request); | |
542 } | |
543 | |
544 private: | |
545 // TODO: unused. | |
546 EmbedApplicationLoader* app_loader_; | |
547 ScopedVector<ApplicationImpl> apps_; | |
548 | |
549 DISALLOW_COPY_AND_ASSIGN(WindowManagerLoader); | |
550 }; | |
551 | |
552 // Creates an id used for transport from the specified parameters. | |
553 Id BuildViewId(ConnectionSpecificId connection_id, | |
554 ConnectionSpecificId view_id) { | |
555 return (connection_id << 16) | view_id; | |
556 } | |
557 | |
558 // Asks the window manager to Embed() the specified URL. | |
559 void WindowManagerEmbed(WindowManager* window_manager, | |
560 const std::string& url, | |
561 size_t number_of_calls) { | |
562 for (size_t i = 0; i < number_of_calls; ++i) { | |
563 ServiceProviderPtr sp; | |
564 window_manager->Embed(url, | |
565 MakeRequest<ServiceProvider>(sp.PassMessagePipe())); | |
566 } | |
567 } | |
568 | |
569 } // namespace | |
570 | |
571 typedef std::vector<std::string> Changes; | |
572 | |
573 class ViewManagerTest : public testing::Test { | |
574 public: | |
575 ViewManagerTest() | |
576 : connection_(NULL), | |
577 connection2_(NULL), | |
578 connection3_(NULL) {} | |
579 | |
580 void SetUp() override { | |
581 ASSERT_TRUE(ViewManagerProxy::IsInInitialState()); | |
582 test_helper_.Init(); | |
583 std::vector<std::string> native_viewport_args; | |
584 native_viewport_args.push_back(kUseTestConfig); | |
585 test_helper_.application_manager()->SetArgsForURL( | |
586 native_viewport_args, GURL("mojo:native_viewport_service")); | |
587 | |
588 #if defined(OS_WIN) | |
589 // As we unload the wndproc of window classes we need to be sure to | |
590 // unregister them. | |
591 gfx::WindowImpl::UnregisterClassesAtExit(); | |
592 #endif | |
593 | |
594 test_helper_.SetLoaderForURL( | |
595 scoped_ptr<ApplicationLoader>(new EmbedApplicationLoader()), | |
596 GURL(kTestServiceURL)); | |
597 | |
598 EmbedApplicationLoader* embed_loader = new EmbedApplicationLoader; | |
599 test_helper_.SetLoaderForURL(scoped_ptr<ApplicationLoader>(embed_loader), | |
600 GURL(kTestServiceURL2)); | |
601 | |
602 test_helper_.SetLoaderForURL( | |
603 scoped_ptr<ApplicationLoader>(new WindowManagerLoader(embed_loader)), | |
604 GURL("mojo:window_manager")); | |
605 | |
606 test_helper_.application_manager()->ConnectToService( | |
607 GURL("mojo:window_manager"), &window_manager_); | |
608 WindowManagerEmbed(window_manager_.get(), kTestServiceURL, 1); | |
609 | |
610 connection_ = ViewManagerProxy::WaitForInstance(); | |
611 ASSERT_TRUE(connection_ != NULL); | |
612 connection_->DoRunLoopUntilChangesCount(1); | |
613 } | |
614 | |
615 void TearDown() override { | |
616 if (connection3_) | |
617 connection3_->Destroy(); | |
618 if (connection2_) | |
619 connection2_->Destroy(); | |
620 // |connection_| is owned by |window_manager_|, no need to destroy it. | |
621 } | |
622 | |
623 protected: | |
624 void EstablishSecondConnectionWithRoot(Id root_id) { | |
625 ASSERT_TRUE(connection_->Embed(root_id, kTestServiceURL)); | |
626 connection2_ = ViewManagerProxy::WaitForInstance(); | |
627 ASSERT_TRUE(connection2_ != NULL); | |
628 connection2_->DoRunLoopUntilChangesCount(1); | |
629 ASSERT_EQ(1u, connection2_->changes().size()); | |
630 } | |
631 | |
632 // Creates a second connection to the viewmanager. | |
633 void EstablishSecondConnection(bool create_initial_view) { | |
634 if (create_initial_view) | |
635 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
636 ASSERT_NO_FATAL_FAILURE( | |
637 EstablishSecondConnectionWithRoot(BuildViewId(1, 1))); | |
638 const std::vector<Change>& changes(connection2_->changes()); | |
639 ASSERT_EQ(1u, changes.size()); | |
640 EXPECT_EQ("OnEmbed creator=mojo:window_manager", | |
641 ChangesToDescription1(changes)[0]); | |
642 if (create_initial_view) | |
643 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes)); | |
644 } | |
645 | |
646 void EstablishThirdConnection(ViewManagerProxy* owner, Id root_id) { | |
647 ASSERT_TRUE(connection3_ == NULL); | |
648 ASSERT_TRUE(owner->Embed(root_id, kTestServiceURL2)); | |
649 connection3_ = ViewManagerProxy::WaitForInstance(); | |
650 ASSERT_TRUE(connection3_ != NULL); | |
651 connection3_->DoRunLoopUntilChangesCount(1); | |
652 ASSERT_EQ(1u, connection3_->changes().size()); | |
653 const std::string expected_creator = | |
654 owner == connection_ ? "mojo:window_manager" : kTestServiceURL; | |
655 EXPECT_EQ("OnEmbed creator=" + expected_creator, | |
656 ChangesToDescription1(connection3_->changes())[0]); | |
657 } | |
658 | |
659 void DestroySecondConnection() { | |
660 connection2_->Destroy(); | |
661 connection2_ = NULL; | |
662 } | |
663 | |
664 base::ShadowingAtExitManager at_exit_; | |
665 shell::ShellTestHelper test_helper_; | |
666 | |
667 WindowManagerPtr window_manager_; | |
668 | |
669 // NOTE: this connection is the root. As such, it has special permissions. | |
670 ViewManagerProxy* connection_; | |
671 ViewManagerProxy* connection2_; | |
672 ViewManagerProxy* connection3_; | |
673 | |
674 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest); | |
675 }; | |
676 | |
677 TEST_F(ViewManagerTest, SecondEmbedRoot_InitService) { | |
678 WindowManagerEmbed(window_manager_.get(), kTestServiceURL, 1); | |
679 connection_->DoRunLoopUntilChangesCount(1); | |
680 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url); | |
681 } | |
682 | |
683 TEST_F(ViewManagerTest, MultipleEmbedRootsBeforeWTHReady) { | |
684 WindowManagerEmbed(window_manager_.get(), kTestServiceURL, 2); | |
685 connection_->DoRunLoopUntilChangesCount(2); | |
686 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url); | |
687 EXPECT_EQ(kTestServiceURL, connection_->changes()[1].embed_url); | |
688 } | |
689 | |
690 // Verifies client gets a valid id. | |
691 // http://crbug.com/396492 | |
692 TEST_F(ViewManagerTest, DISABLED_ValidId) { | |
693 // TODO(beng): this should really have the URL of the application that | |
694 // connected to ViewManagerInit. | |
695 EXPECT_EQ("OnEmbed creator=", | |
696 ChangesToDescription1(connection_->changes())[0]); | |
697 | |
698 // All these tests assume 1 for the client id. The only real assertion here is | |
699 // the client id is not zero, but adding this as rest of code here assumes 1. | |
700 EXPECT_EQ(1, connection_->changes()[0].connection_id); | |
701 } | |
702 | |
703 // Verifies two clients/connections get different ids. | |
704 TEST_F(ViewManagerTest, TwoClientsGetDifferentConnectionIds) { | |
705 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
706 EXPECT_EQ("OnEmbed creator=mojo:window_manager", | |
707 ChangesToDescription1(connection2_->changes())[0]); | |
708 | |
709 // It isn't strictly necessary that the second connection gets 2, but these | |
710 // tests are written assuming that is the case. The key thing is the | |
711 // connection ids of |connection_| and |connection2_| differ. | |
712 EXPECT_EQ(2, connection2_->changes()[0].connection_id); | |
713 } | |
714 | |
715 // Verifies when Embed() is invoked any child views are removed. | |
716 TEST_F(ViewManagerTest, ViewsRemovedWhenEmbedding) { | |
717 // Two views 1 and 2. 2 is parented to 1. | |
718 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
719 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
720 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); | |
721 | |
722 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
723 EXPECT_EQ("[view=1,1 parent=null]", | |
724 ChangeViewDescription(connection2_->changes())); | |
725 | |
726 // Embed() removed view 2. | |
727 { | |
728 std::vector<TestView> views; | |
729 connection_->GetViewTree(BuildViewId(1, 2), &views); | |
730 ASSERT_EQ(1u, views.size()); | |
731 EXPECT_EQ("view=1,2 parent=null", views[0].ToString()); | |
732 } | |
733 | |
734 // |connection2_| should not see view 2. | |
735 { | |
736 std::vector<TestView> views; | |
737 connection2_->GetViewTree(BuildViewId(1, 1), &views); | |
738 ASSERT_EQ(1u, views.size()); | |
739 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); | |
740 } | |
741 { | |
742 std::vector<TestView> views; | |
743 connection2_->GetViewTree(BuildViewId(1, 2), &views); | |
744 EXPECT_TRUE(views.empty()); | |
745 } | |
746 | |
747 // Views 3 and 4 in connection 2. | |
748 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); | |
749 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 4))); | |
750 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 3), BuildViewId(2, 4))); | |
751 | |
752 // Connection 3 rooted at 2. | |
753 ASSERT_NO_FATAL_FAILURE( | |
754 EstablishThirdConnection(connection2_, BuildViewId(2, 3))); | |
755 | |
756 // View 4 should no longer have a parent. | |
757 { | |
758 std::vector<TestView> views; | |
759 connection2_->GetViewTree(BuildViewId(2, 3), &views); | |
760 ASSERT_EQ(1u, views.size()); | |
761 EXPECT_EQ("view=2,3 parent=null", views[0].ToString()); | |
762 | |
763 views.clear(); | |
764 connection2_->GetViewTree(BuildViewId(2, 4), &views); | |
765 ASSERT_EQ(1u, views.size()); | |
766 EXPECT_EQ("view=2,4 parent=null", views[0].ToString()); | |
767 } | |
768 | |
769 // And view 4 should not be visible to connection 3. | |
770 { | |
771 std::vector<TestView> views; | |
772 connection3_->GetViewTree(BuildViewId(2, 3), &views); | |
773 ASSERT_EQ(1u, views.size()); | |
774 EXPECT_EQ("view=2,3 parent=null", views[0].ToString()); | |
775 } | |
776 } | |
777 | |
778 // Verifies once Embed() has been invoked the parent connection can't see any | |
779 // children. | |
780 TEST_F(ViewManagerTest, CantAccessChildrenOfEmbeddedView) { | |
781 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
782 | |
783 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
784 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
785 | |
786 ASSERT_NO_FATAL_FAILURE( | |
787 EstablishThirdConnection(connection2_, BuildViewId(2, 2))); | |
788 | |
789 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 3))); | |
790 ASSERT_TRUE(connection3_->AddView(BuildViewId(2, 2), BuildViewId(3, 3))); | |
791 | |
792 // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a | |
793 // different connection. | |
794 { | |
795 std::vector<TestView> views; | |
796 connection2_->GetViewTree(BuildViewId(2, 2), &views); | |
797 ASSERT_EQ(1u, views.size()); | |
798 EXPECT_EQ("view=2,2 parent=1,1", views[0].ToString()); | |
799 } | |
800 | |
801 { | |
802 std::vector<TestView> views; | |
803 connection2_->GetViewTree(BuildViewId(3, 3), &views); | |
804 EXPECT_TRUE(views.empty()); | |
805 } | |
806 | |
807 // Connection 2 shouldn't be able to get view 3 at all. | |
808 { | |
809 std::vector<TestView> views; | |
810 connection2_->GetViewTree(BuildViewId(3, 3), &views); | |
811 EXPECT_TRUE(views.empty()); | |
812 } | |
813 | |
814 // Connection 1 should be able to see it all (its the root). | |
815 { | |
816 std::vector<TestView> views; | |
817 connection_->GetViewTree(BuildViewId(1, 1), &views); | |
818 ASSERT_EQ(3u, views.size()); | |
819 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); | |
820 EXPECT_EQ("view=2,2 parent=1,1", views[1].ToString()); | |
821 EXPECT_EQ("view=3,3 parent=2,2", views[2].ToString()); | |
822 } | |
823 } | |
824 | |
825 // Verifies once Embed() has been invoked the parent can't mutate the children. | |
826 TEST_F(ViewManagerTest, CantModifyChildrenOfEmbeddedView) { | |
827 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
828 | |
829 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
830 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
831 | |
832 ASSERT_NO_FATAL_FAILURE( | |
833 EstablishThirdConnection(connection2_, BuildViewId(2, 2))); | |
834 | |
835 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); | |
836 // Connection 2 shouldn't be able to add anything to the view anymore. | |
837 ASSERT_FALSE(connection2_->AddView(BuildViewId(2, 2), BuildViewId(2, 3))); | |
838 | |
839 // Create view 3 in connection 3 and add it to view 3. | |
840 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 3))); | |
841 ASSERT_TRUE(connection3_->AddView(BuildViewId(2, 2), BuildViewId(3, 3))); | |
842 | |
843 // Connection 2 shouldn't be able to remove view 3. | |
844 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(3, 3))); | |
845 } | |
846 | |
847 // Verifies client gets a valid id. | |
848 TEST_F(ViewManagerTest, CreateView) { | |
849 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
850 EXPECT_TRUE(connection_->changes().empty()); | |
851 | |
852 // Can't create a view with the same id. | |
853 ASSERT_EQ(ERROR_CODE_VALUE_IN_USE, | |
854 connection_->CreateViewWithErrorCode(BuildViewId(1, 1))); | |
855 EXPECT_TRUE(connection_->changes().empty()); | |
856 | |
857 // Can't create a view with a bogus connection id. | |
858 EXPECT_EQ(ERROR_CODE_ILLEGAL_ARGUMENT, | |
859 connection_->CreateViewWithErrorCode(BuildViewId(2, 1))); | |
860 EXPECT_TRUE(connection_->changes().empty()); | |
861 } | |
862 | |
863 // Verifies AddView fails when view is already in position. | |
864 TEST_F(ViewManagerTest, AddViewWithNoChange) { | |
865 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
866 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3))); | |
867 | |
868 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
869 | |
870 // Make 3 a child of 2. | |
871 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3))); | |
872 | |
873 // Try again, this should fail. | |
874 EXPECT_FALSE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3))); | |
875 } | |
876 | |
877 // Verifies AddView fails when view is already in position. | |
878 TEST_F(ViewManagerTest, AddAncestorFails) { | |
879 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
880 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3))); | |
881 | |
882 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
883 | |
884 // Make 3 a child of 2. | |
885 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3))); | |
886 | |
887 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3. | |
888 EXPECT_FALSE(connection_->AddView(BuildViewId(1, 3), BuildViewId(1, 2))); | |
889 } | |
890 | |
891 // Verifies adding to root sends right notifications. | |
892 TEST_F(ViewManagerTest, AddToRoot) { | |
893 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 21))); | |
894 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3))); | |
895 | |
896 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
897 | |
898 // Make 3 a child of 21. | |
899 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 21), BuildViewId(1, 3))); | |
900 | |
901 // Make 21 a child of 1. | |
902 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 21))); | |
903 | |
904 // Connection 2 should not be told anything (because the view is from a | |
905 // different connection). Create a view to ensure we got a response from | |
906 // the server. | |
907 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 100))); | |
908 connection2_->CopyChangesFromTracker(); | |
909 EXPECT_TRUE(connection2_->changes().empty()); | |
910 } | |
911 | |
912 // Verifies HierarchyChanged is correctly sent for various adds/removes. | |
913 TEST_F(ViewManagerTest, ViewHierarchyChangedViews) { | |
914 // 1,2->1,11. | |
915 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
916 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 2), true)); | |
917 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 11))); | |
918 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 11), true)); | |
919 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 11))); | |
920 | |
921 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
922 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); | |
923 | |
924 // 1,1->1,2->1,11 | |
925 { | |
926 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 101))); | |
927 // Client 2 should not get anything (1,2 is from another connection). | |
928 connection2_->ClearChanges(); | |
929 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); | |
930 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 100))); | |
931 connection2_->CopyChangesFromTracker(); | |
932 EXPECT_TRUE(connection2_->changes().empty()); | |
933 } | |
934 | |
935 // 0,1->1,1->1,2->1,11. | |
936 { | |
937 // Client 2 is now connected to the root, so it should have gotten a drawn | |
938 // notification. | |
939 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
940 connection2_->DoRunLoopUntilChangesCount(1); | |
941 ASSERT_EQ(1u, connection2_->changes().size()); | |
942 EXPECT_EQ("DrawnStateChanged view=1,1 drawn=true", | |
943 ChangesToDescription1(connection2_->changes())[0]); | |
944 } | |
945 | |
946 // 1,1->1,2->1,11. | |
947 { | |
948 // Client 2 is no longer connected to the root, should get drawn state | |
949 // changed. | |
950 ASSERT_TRUE(connection_->RemoveViewFromParent(BuildViewId(1, 1))); | |
951 connection2_->DoRunLoopUntilChangesCount(1); | |
952 ASSERT_EQ(1u, connection2_->changes().size()); | |
953 EXPECT_EQ("DrawnStateChanged view=1,1 drawn=false", | |
954 ChangesToDescription1(connection2_->changes())[0]); | |
955 } | |
956 | |
957 // 1,1->1,2->1,11->1,111. | |
958 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 111))); | |
959 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 111), true)); | |
960 { | |
961 connection2_->ClearChanges(); | |
962 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 11), BuildViewId(1, 111))); | |
963 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 103))); | |
964 connection2_->CopyChangesFromTracker(); | |
965 EXPECT_TRUE(connection2_->changes().empty()); | |
966 } | |
967 | |
968 // 0,1->1,1->1,2->1,11->1,111 | |
969 { | |
970 connection2_->ClearChanges(); | |
971 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
972 connection2_->DoRunLoopUntilChangesCount(1); | |
973 ASSERT_EQ(1u, connection2_->changes().size()); | |
974 EXPECT_EQ("DrawnStateChanged view=1,1 drawn=true", | |
975 ChangesToDescription1(connection2_->changes())[0]); | |
976 } | |
977 } | |
978 | |
979 TEST_F(ViewManagerTest, ViewHierarchyChangedAddingKnownToUnknown) { | |
980 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no | |
981 // parent). | |
982 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
983 | |
984 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 11))); | |
985 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
986 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 21))); | |
987 | |
988 // Set up the hierarchy. | |
989 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
990 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 11))); | |
991 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 2), BuildViewId(2, 21))); | |
992 | |
993 // Remove 11, should result in a hierarchy change for the root. | |
994 { | |
995 connection_->ClearChanges(); | |
996 ASSERT_TRUE(connection2_->RemoveViewFromParent(BuildViewId(2, 11))); | |
997 | |
998 connection_->DoRunLoopUntilChangesCount(1); | |
999 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1000 ASSERT_EQ(1u, changes.size()); | |
1001 EXPECT_EQ("HierarchyChanged view=2,11 new_parent=null old_parent=1,1", | |
1002 changes[0]); | |
1003 } | |
1004 | |
1005 // Add 2 to 1. | |
1006 { | |
1007 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
1008 | |
1009 connection_->DoRunLoopUntilChangesCount(1); | |
1010 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1011 ASSERT_EQ(1u, changes.size()); | |
1012 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", | |
1013 changes[0]); | |
1014 EXPECT_EQ( | |
1015 "[view=2,2 parent=1,1]," | |
1016 "[view=2,21 parent=2,2]", | |
1017 ChangeViewDescription(connection_->changes())); | |
1018 } | |
1019 } | |
1020 | |
1021 TEST_F(ViewManagerTest, ReorderView) { | |
1022 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1023 | |
1024 Id view1_id = BuildViewId(2, 1); | |
1025 Id view2_id = BuildViewId(2, 2); | |
1026 Id view3_id = BuildViewId(2, 3); | |
1027 Id view4_id = BuildViewId(1, 4); // Peer to 1,1 | |
1028 Id view5_id = BuildViewId(1, 5); // Peer to 1,1 | |
1029 Id view6_id = BuildViewId(2, 6); // Child of 1,2. | |
1030 Id view7_id = BuildViewId(2, 7); // Unparented. | |
1031 Id view8_id = BuildViewId(2, 8); // Unparented. | |
1032 ASSERT_TRUE(connection2_->CreateView(view1_id)); | |
1033 ASSERT_TRUE(connection2_->CreateView(view2_id)); | |
1034 ASSERT_TRUE(connection2_->CreateView(view3_id)); | |
1035 ASSERT_TRUE(connection_->CreateView(view4_id)); | |
1036 ASSERT_TRUE(connection_->CreateView(view5_id)); | |
1037 ASSERT_TRUE(connection2_->CreateView(view6_id)); | |
1038 ASSERT_TRUE(connection2_->CreateView(view7_id)); | |
1039 ASSERT_TRUE(connection2_->CreateView(view8_id)); | |
1040 ASSERT_TRUE(connection2_->AddView(view1_id, view2_id)); | |
1041 ASSERT_TRUE(connection2_->AddView(view2_id, view6_id)); | |
1042 ASSERT_TRUE(connection2_->AddView(view1_id, view3_id)); | |
1043 ASSERT_TRUE( | |
1044 connection_->AddView(ViewIdToTransportId(RootViewId()), view4_id)); | |
1045 ASSERT_TRUE( | |
1046 connection_->AddView(ViewIdToTransportId(RootViewId()), view5_id)); | |
1047 | |
1048 ASSERT_TRUE( | |
1049 connection_->AddView(ViewIdToTransportId(RootViewId()), view1_id)); | |
1050 | |
1051 { | |
1052 ASSERT_TRUE( | |
1053 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_ABOVE)); | |
1054 | |
1055 connection_->DoRunLoopUntilChangesCount(1); | |
1056 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1057 ASSERT_EQ(1u, changes.size()); | |
1058 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=above", changes[0]); | |
1059 } | |
1060 | |
1061 { | |
1062 ASSERT_TRUE( | |
1063 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_BELOW)); | |
1064 | |
1065 connection_->DoRunLoopUntilChangesCount(1); | |
1066 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1067 ASSERT_EQ(1u, changes.size()); | |
1068 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=below", changes[0]); | |
1069 } | |
1070 | |
1071 // view2 is already below view3. | |
1072 EXPECT_FALSE( | |
1073 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_BELOW)); | |
1074 | |
1075 // view4 & 5 are unknown to connection2_. | |
1076 EXPECT_FALSE( | |
1077 connection2_->ReorderView(view4_id, view5_id, ORDER_DIRECTION_ABOVE)); | |
1078 | |
1079 // view6 & view3 have different parents. | |
1080 EXPECT_FALSE( | |
1081 connection_->ReorderView(view3_id, view6_id, ORDER_DIRECTION_ABOVE)); | |
1082 | |
1083 // Non-existent view-ids | |
1084 EXPECT_FALSE(connection_->ReorderView( | |
1085 BuildViewId(1, 27), BuildViewId(1, 28), ORDER_DIRECTION_ABOVE)); | |
1086 | |
1087 // view7 & view8 are un-parented. | |
1088 EXPECT_FALSE( | |
1089 connection_->ReorderView(view7_id, view8_id, ORDER_DIRECTION_ABOVE)); | |
1090 } | |
1091 | |
1092 // Verifies DeleteView works. | |
1093 TEST_F(ViewManagerTest, DeleteView) { | |
1094 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1095 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
1096 | |
1097 // Make 2 a child of 1. | |
1098 { | |
1099 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
1100 connection_->DoRunLoopUntilChangesCount(1); | |
1101 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1102 ASSERT_EQ(1u, changes.size()); | |
1103 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", | |
1104 changes[0]); | |
1105 } | |
1106 | |
1107 // Delete 2. | |
1108 { | |
1109 ASSERT_TRUE(connection2_->DeleteView(BuildViewId(2, 2))); | |
1110 EXPECT_TRUE(connection2_->changes().empty()); | |
1111 | |
1112 connection_->DoRunLoopUntilChangesCount(1); | |
1113 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1114 ASSERT_EQ(1u, changes.size()); | |
1115 EXPECT_EQ("ViewDeleted view=2,2", changes[0]); | |
1116 } | |
1117 } | |
1118 | |
1119 // Verifies DeleteView isn't allowed from a separate connection. | |
1120 TEST_F(ViewManagerTest, DeleteViewFromAnotherConnectionDisallowed) { | |
1121 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1122 EXPECT_FALSE(connection2_->DeleteView(BuildViewId(1, 1))); | |
1123 } | |
1124 | |
1125 // Verifies if a view was deleted and then reused that other clients are | |
1126 // properly notified. | |
1127 TEST_F(ViewManagerTest, ReuseDeletedViewId) { | |
1128 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1129 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
1130 | |
1131 // Add 2 to 1. | |
1132 { | |
1133 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
1134 | |
1135 connection_->DoRunLoopUntilChangesCount(1); | |
1136 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1137 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", | |
1138 changes[0]); | |
1139 EXPECT_EQ("[view=2,2 parent=1,1]", | |
1140 ChangeViewDescription(connection_->changes())); | |
1141 } | |
1142 | |
1143 // Delete 2. | |
1144 { | |
1145 ASSERT_TRUE(connection2_->DeleteView(BuildViewId(2, 2))); | |
1146 | |
1147 connection_->DoRunLoopUntilChangesCount(1); | |
1148 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1149 ASSERT_EQ(1u, changes.size()); | |
1150 EXPECT_EQ("ViewDeleted view=2,2", changes[0]); | |
1151 } | |
1152 | |
1153 // Create 2 again, and add it back to 1. Should get the same notification. | |
1154 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
1155 { | |
1156 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
1157 | |
1158 connection_->DoRunLoopUntilChangesCount(1); | |
1159 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1160 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null", | |
1161 changes[0]); | |
1162 EXPECT_EQ("[view=2,2 parent=1,1]", | |
1163 ChangeViewDescription(connection_->changes())); | |
1164 } | |
1165 } | |
1166 | |
1167 // Assertions for GetViewTree. | |
1168 TEST_F(ViewManagerTest, GetViewTree) { | |
1169 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1170 | |
1171 // Create 11 in first connection and make it a child of 1. | |
1172 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 11))); | |
1173 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1174 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 11))); | |
1175 | |
1176 // Create two views in second connection, 2 and 3, both children of 1. | |
1177 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2))); | |
1178 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); | |
1179 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2))); | |
1180 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 3))); | |
1181 | |
1182 // Verifies GetViewTree() on the root. The root connection sees all. | |
1183 { | |
1184 std::vector<TestView> views; | |
1185 connection_->GetViewTree(BuildViewId(0, 1), &views); | |
1186 ASSERT_EQ(5u, views.size()); | |
1187 EXPECT_EQ("view=0,1 parent=null", views[0].ToString()); | |
1188 EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString()); | |
1189 EXPECT_EQ("view=1,11 parent=1,1", views[2].ToString()); | |
1190 EXPECT_EQ("view=2,2 parent=1,1", views[3].ToString()); | |
1191 EXPECT_EQ("view=2,3 parent=1,1", views[4].ToString()); | |
1192 } | |
1193 | |
1194 // Verifies GetViewTree() from connection2 for 1,1. connection2 should see 1,1 | |
1195 // as 1,1 is the root for connection2 and all of 1,1's children as connection2 | |
1196 // created them. | |
1197 { | |
1198 std::vector<TestView> views; | |
1199 connection2_->GetViewTree(BuildViewId(1, 1), &views); | |
1200 ASSERT_EQ(3u, views.size()); | |
1201 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); | |
1202 EXPECT_EQ("view=2,2 parent=1,1", views[1].ToString()); | |
1203 EXPECT_EQ("view=2,3 parent=1,1", views[2].ToString()); | |
1204 } | |
1205 | |
1206 // Connection 2 shouldn't be able to get the root tree. | |
1207 { | |
1208 std::vector<TestView> views; | |
1209 connection2_->GetViewTree(BuildViewId(0, 1), &views); | |
1210 ASSERT_EQ(0u, views.size()); | |
1211 } | |
1212 } | |
1213 | |
1214 TEST_F(ViewManagerTest, SetViewBounds) { | |
1215 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1216 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1217 | |
1218 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
1219 | |
1220 ASSERT_TRUE( | |
1221 connection_->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 100, 100))); | |
1222 | |
1223 connection2_->DoRunLoopUntilChangesCount(1); | |
1224 const Changes changes(ChangesToDescription1(connection2_->changes())); | |
1225 ASSERT_EQ(1u, changes.size()); | |
1226 EXPECT_EQ("BoundsChanged view=1,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100", | |
1227 changes[0]); | |
1228 | |
1229 // Should not be possible to change the bounds of a view created by another | |
1230 // connection. | |
1231 ASSERT_FALSE( | |
1232 connection2_->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 0, 0))); | |
1233 } | |
1234 | |
1235 // Verify AddView fails when trying to manipulate views in other roots. | |
1236 TEST_F(ViewManagerTest, CantMoveViewsFromOtherRoot) { | |
1237 // Create 1 and 2 in the first connection. | |
1238 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1239 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
1240 | |
1241 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
1242 | |
1243 // Try to move 2 to be a child of 1 from connection 2. This should fail as 2 | |
1244 // should not be able to access 1. | |
1245 ASSERT_FALSE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); | |
1246 | |
1247 // Try to reparent 1 to the root. A connection is not allowed to reparent its | |
1248 // roots. | |
1249 ASSERT_FALSE(connection2_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1250 } | |
1251 | |
1252 // Verify RemoveViewFromParent fails for views that are descendants of the | |
1253 // roots. | |
1254 TEST_F(ViewManagerTest, CantRemoveViewsInOtherRoots) { | |
1255 // Create 1 and 2 in the first connection and parent both to the root. | |
1256 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1257 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
1258 | |
1259 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1260 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 2))); | |
1261 | |
1262 // Establish the second connection and give it the root 1. | |
1263 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
1264 | |
1265 // Connection 2 should not be able to remove view 2 or 1 from its parent. | |
1266 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(1, 2))); | |
1267 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(1, 1))); | |
1268 | |
1269 // Create views 10 and 11 in 2. | |
1270 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 10))); | |
1271 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 11))); | |
1272 | |
1273 // Parent 11 to 10. | |
1274 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 10), BuildViewId(2, 11))); | |
1275 // Remove 11 from 10. | |
1276 ASSERT_TRUE(connection2_->RemoveViewFromParent(BuildViewId(2, 11))); | |
1277 | |
1278 // Verify nothing was actually removed. | |
1279 { | |
1280 std::vector<TestView> views; | |
1281 connection_->GetViewTree(BuildViewId(0, 1), &views); | |
1282 ASSERT_EQ(3u, views.size()); | |
1283 EXPECT_EQ("view=0,1 parent=null", views[0].ToString()); | |
1284 EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString()); | |
1285 EXPECT_EQ("view=1,2 parent=0,1", views[2].ToString()); | |
1286 } | |
1287 } | |
1288 | |
1289 // Verify GetViewTree fails for views that are not descendants of the roots. | |
1290 TEST_F(ViewManagerTest, CantGetViewTreeOfOtherRoots) { | |
1291 // Create 1 and 2 in the first connection and parent both to the root. | |
1292 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1293 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
1294 | |
1295 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1296 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 2))); | |
1297 | |
1298 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
1299 | |
1300 std::vector<TestView> views; | |
1301 | |
1302 // Should get nothing for the root. | |
1303 connection2_->GetViewTree(BuildViewId(0, 1), &views); | |
1304 ASSERT_TRUE(views.empty()); | |
1305 | |
1306 // Should get nothing for view 2. | |
1307 connection2_->GetViewTree(BuildViewId(1, 2), &views); | |
1308 ASSERT_TRUE(views.empty()); | |
1309 | |
1310 // Should get view 1 if asked for. | |
1311 connection2_->GetViewTree(BuildViewId(1, 1), &views); | |
1312 ASSERT_EQ(1u, views.size()); | |
1313 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); | |
1314 } | |
1315 | |
1316 TEST_F(ViewManagerTest, OnViewInput) { | |
1317 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1318 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
1319 | |
1320 // Dispatch an event to the view and verify its received. | |
1321 { | |
1322 EventPtr event(Event::New()); | |
1323 event->action = static_cast<EventType>(1); | |
1324 connection_->window_manager_client()->DispatchInputEventToView( | |
1325 BuildViewId(1, 1), event.Pass()); | |
1326 connection2_->DoRunLoopUntilChangesCount(1); | |
1327 const Changes changes(ChangesToDescription1(connection2_->changes())); | |
1328 ASSERT_EQ(1u, changes.size()); | |
1329 EXPECT_EQ("InputEvent view=1,1 event_action=1", changes[0]); | |
1330 } | |
1331 } | |
1332 | |
1333 TEST_F(ViewManagerTest, EmbedWithSameViewId) { | |
1334 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1335 | |
1336 ASSERT_NO_FATAL_FAILURE( | |
1337 EstablishThirdConnection(connection_, BuildViewId(1, 1))); | |
1338 | |
1339 // Connection2 should have been told the view was deleted. | |
1340 { | |
1341 connection2_->DoRunLoopUntilChangesCount(1); | |
1342 const Changes changes(ChangesToDescription1(connection2_->changes())); | |
1343 ASSERT_EQ(1u, changes.size()); | |
1344 EXPECT_EQ("ViewDeleted view=1,1", changes[0]); | |
1345 } | |
1346 | |
1347 // Connection2 has no root. Verify it can't see view 1,1 anymore. | |
1348 { | |
1349 std::vector<TestView> views; | |
1350 connection2_->GetViewTree(BuildViewId(1, 1), &views); | |
1351 EXPECT_TRUE(views.empty()); | |
1352 } | |
1353 } | |
1354 | |
1355 TEST_F(ViewManagerTest, EmbedWithSameViewId2) { | |
1356 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); | |
1357 | |
1358 ASSERT_NO_FATAL_FAILURE( | |
1359 EstablishThirdConnection(connection_, BuildViewId(1, 1))); | |
1360 | |
1361 // Connection2 should have been told the view was deleted. | |
1362 connection2_->DoRunLoopUntilChangesCount(1); | |
1363 connection2_->ClearChanges(); | |
1364 | |
1365 // Create a view in the third connection and parent it to the root. | |
1366 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 1))); | |
1367 ASSERT_TRUE(connection3_->AddView(BuildViewId(1, 1), BuildViewId(3, 1))); | |
1368 | |
1369 // Connection 1 should have been told about the add (it owns the view). | |
1370 { | |
1371 connection_->DoRunLoopUntilChangesCount(1); | |
1372 const Changes changes(ChangesToDescription1(connection_->changes())); | |
1373 ASSERT_EQ(1u, changes.size()); | |
1374 EXPECT_EQ("HierarchyChanged view=3,1 new_parent=1,1 old_parent=null", | |
1375 changes[0]); | |
1376 } | |
1377 | |
1378 // Embed 1,1 again. | |
1379 { | |
1380 // We should get a new connection for the new embedding. | |
1381 ASSERT_TRUE(connection_->Embed(BuildViewId(1, 1), kTestServiceURL)); | |
1382 ViewManagerProxy* connection4 = ViewManagerProxy::WaitForInstance(); | |
1383 connection4->DoRunLoopUntilChangesCount(1); | |
1384 const std::vector<Change>& changes(connection4->changes()); | |
1385 ASSERT_EQ(1u, changes.size()); | |
1386 EXPECT_EQ("OnEmbed creator=mojo:window_manager", | |
1387 ChangesToDescription1(changes)[0]); | |
1388 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes)); | |
1389 | |
1390 // And 3 should get a delete. | |
1391 connection3_->DoRunLoopUntilChangesCount(1); | |
1392 ASSERT_EQ(1u, connection3_->changes().size()); | |
1393 EXPECT_EQ("ViewDeleted view=1,1", | |
1394 ChangesToDescription1(connection3_->changes())[0]); | |
1395 } | |
1396 | |
1397 // Connection3_ has no root. Verify it can't see view 1,1 anymore. | |
1398 { | |
1399 std::vector<TestView> views; | |
1400 connection3_->GetViewTree(BuildViewId(1, 1), &views); | |
1401 EXPECT_TRUE(views.empty()); | |
1402 } | |
1403 | |
1404 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as | |
1405 // connection3_ can no longer see 1,1. | |
1406 { | |
1407 std::vector<TestView> views; | |
1408 connection_->GetViewTree(BuildViewId(1, 1), &views); | |
1409 ASSERT_EQ(1u, views.size()); | |
1410 EXPECT_EQ("view=1,1 parent=null", views[0].ToString()); | |
1411 } | |
1412 | |
1413 // Verify connection3_ can still see the view it created 3,1. | |
1414 { | |
1415 std::vector<TestView> views; | |
1416 connection3_->GetViewTree(BuildViewId(3, 1), &views); | |
1417 ASSERT_EQ(1u, views.size()); | |
1418 EXPECT_EQ("view=3,1 parent=null", views[0].ToString()); | |
1419 } | |
1420 } | |
1421 | |
1422 // Assertions for SetViewVisibility. | |
1423 TEST_F(ViewManagerTest, SetViewVisibility) { | |
1424 // Create 1 and 2 in the first connection and parent both to the root. | |
1425 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1426 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
1427 | |
1428 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1429 { | |
1430 std::vector<TestView> views; | |
1431 connection_->GetViewTree(BuildViewId(0, 1), &views); | |
1432 ASSERT_EQ(2u, views.size()); | |
1433 EXPECT_EQ("view=0,1 parent=null visible=true drawn=true", | |
1434 views[0].ToString2()); | |
1435 EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false", | |
1436 views[1].ToString2()); | |
1437 } | |
1438 | |
1439 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); | |
1440 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 2), true)); | |
1441 { | |
1442 std::vector<TestView> views; | |
1443 connection_->GetViewTree(BuildViewId(0, 1), &views); | |
1444 ASSERT_EQ(2u, views.size()); | |
1445 EXPECT_EQ("view=0,1 parent=null visible=true drawn=true", | |
1446 views[0].ToString2()); | |
1447 EXPECT_EQ("view=1,1 parent=0,1 visible=true drawn=true", | |
1448 views[1].ToString2()); | |
1449 } | |
1450 | |
1451 // Hide 1. | |
1452 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), false)); | |
1453 { | |
1454 std::vector<TestView> views; | |
1455 connection_->GetViewTree(BuildViewId(1, 1), &views); | |
1456 ASSERT_EQ(1u, views.size()); | |
1457 EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false", | |
1458 views[0].ToString2()); | |
1459 } | |
1460 | |
1461 // Attach 2 to 1. | |
1462 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); | |
1463 { | |
1464 std::vector<TestView> views; | |
1465 connection_->GetViewTree(BuildViewId(1, 1), &views); | |
1466 ASSERT_EQ(2u, views.size()); | |
1467 EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false", | |
1468 views[0].ToString2()); | |
1469 EXPECT_EQ("view=1,2 parent=1,1 visible=true drawn=false", | |
1470 views[1].ToString2()); | |
1471 } | |
1472 | |
1473 // Show 1. | |
1474 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); | |
1475 { | |
1476 std::vector<TestView> views; | |
1477 connection_->GetViewTree(BuildViewId(1, 1), &views); | |
1478 ASSERT_EQ(2u, views.size()); | |
1479 EXPECT_EQ("view=1,1 parent=0,1 visible=true drawn=true", | |
1480 views[0].ToString2()); | |
1481 EXPECT_EQ("view=1,2 parent=1,1 visible=true drawn=true", | |
1482 views[1].ToString2()); | |
1483 } | |
1484 } | |
1485 | |
1486 // Assertions for SetViewVisibility sending notifications. | |
1487 TEST_F(ViewManagerTest, SetViewVisibilityNotifications) { | |
1488 // Create 1,1 and 1,2, 1,2 and child of 1,1 and 1,1 a child of the root. | |
1489 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1490 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); | |
1491 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2))); | |
1492 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 2), true)); | |
1493 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1494 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2))); | |
1495 | |
1496 // Establish the second connection at 1,2. | |
1497 ASSERT_NO_FATAL_FAILURE( | |
1498 EstablishSecondConnectionWithRoot(BuildViewId(1, 2))); | |
1499 | |
1500 // Add 2,3 as a child of 1,2. | |
1501 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3))); | |
1502 ASSERT_TRUE(connection2_->SetViewVisibility(BuildViewId(2, 3), true)); | |
1503 connection_->ClearChanges(); | |
1504 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 2), BuildViewId(2, 3))); | |
1505 connection_->DoRunLoopUntilChangesCount(1); | |
1506 | |
1507 // Hide 1,2 from connection 1. Connection 2 should see this. | |
1508 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 2), false)); | |
1509 { | |
1510 connection2_->DoRunLoopUntilChangesCount(1); | |
1511 ASSERT_EQ(1u, connection2_->changes().size()); | |
1512 EXPECT_EQ("VisibilityChanged view=1,2 visible=false", | |
1513 ChangesToDescription1(connection2_->changes())[0]); | |
1514 } | |
1515 | |
1516 // Show 1,2 from connection 2, connection 1 should be notified. | |
1517 ASSERT_TRUE(connection2_->SetViewVisibility(BuildViewId(1, 2), true)); | |
1518 { | |
1519 connection_->DoRunLoopUntilChangesCount(1); | |
1520 ASSERT_EQ(1u, connection_->changes().size()); | |
1521 EXPECT_EQ("VisibilityChanged view=1,2 visible=true", | |
1522 ChangesToDescription1(connection_->changes())[0]); | |
1523 } | |
1524 | |
1525 // Hide 1,1, connection 2 should be told the draw state changed. | |
1526 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), false)); | |
1527 { | |
1528 connection2_->DoRunLoopUntilChangesCount(1); | |
1529 ASSERT_EQ(1u, connection2_->changes().size()); | |
1530 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=false", | |
1531 ChangesToDescription1(connection2_->changes())[0]); | |
1532 } | |
1533 | |
1534 // Show 1,1 from connection 1. Connection 2 should see this. | |
1535 ASSERT_TRUE(connection_->SetViewVisibility(BuildViewId(1, 1), true)); | |
1536 { | |
1537 connection2_->DoRunLoopUntilChangesCount(1); | |
1538 ASSERT_EQ(1u, connection2_->changes().size()); | |
1539 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=true", | |
1540 ChangesToDescription1(connection2_->changes())[0]); | |
1541 } | |
1542 | |
1543 // Change visibility of 2,3, connection 1 should see this. | |
1544 connection_->ClearChanges(); | |
1545 ASSERT_TRUE(connection2_->SetViewVisibility(BuildViewId(2, 3), false)); | |
1546 { | |
1547 connection_->DoRunLoopUntilChangesCount(1); | |
1548 ASSERT_EQ(1u, connection_->changes().size()); | |
1549 EXPECT_EQ("VisibilityChanged view=2,3 visible=false", | |
1550 ChangesToDescription1(connection_->changes())[0]); | |
1551 } | |
1552 | |
1553 // Remove 1,1 from the root, connection 2 should see drawn state changed. | |
1554 ASSERT_TRUE(connection_->RemoveViewFromParent(BuildViewId(1, 1))); | |
1555 { | |
1556 connection2_->DoRunLoopUntilChangesCount(1); | |
1557 ASSERT_EQ(1u, connection2_->changes().size()); | |
1558 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=false", | |
1559 ChangesToDescription1(connection2_->changes())[0]); | |
1560 } | |
1561 | |
1562 // Add 1,1 back to the root, connection 2 should see drawn state changed. | |
1563 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1564 { | |
1565 connection2_->DoRunLoopUntilChangesCount(1); | |
1566 ASSERT_EQ(1u, connection2_->changes().size()); | |
1567 EXPECT_EQ("DrawnStateChanged view=1,2 drawn=true", | |
1568 ChangesToDescription1(connection2_->changes())[0]); | |
1569 } | |
1570 } | |
1571 | |
1572 TEST_F(ViewManagerTest, SetViewProperty) { | |
1573 // Create 1 and 2 in the first connection and parent both to the root. | |
1574 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1))); | |
1575 | |
1576 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false)); | |
1577 | |
1578 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1))); | |
1579 { | |
1580 std::vector<TestView> views; | |
1581 connection_->GetViewTree(BuildViewId(0, 1), &views); | |
1582 ASSERT_EQ(2u, views.size()); | |
1583 EXPECT_EQ("view=0,1 parent=null visible=true drawn=true", | |
1584 views[0].ToString2()); | |
1585 EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false", | |
1586 views[1].ToString2()); | |
1587 | |
1588 ASSERT_EQ(0u, views[1].properties.size()); | |
1589 } | |
1590 | |
1591 // Set properties on 1. | |
1592 std::vector<uint8_t> one(1, '1'); | |
1593 ASSERT_TRUE(connection_->SetViewProperty(BuildViewId(1, 1), "one", &one)); | |
1594 { | |
1595 connection2_->DoRunLoopUntilChangesCount(1); | |
1596 ASSERT_EQ(1u, connection2_->changes().size()); | |
1597 EXPECT_EQ("PropertyChanged view=1,1 key=one value=1", | |
1598 ChangesToDescription1(connection2_->changes())[0]); | |
1599 } | |
1600 | |
1601 // Test that our properties exist in the view tree | |
1602 { | |
1603 std::vector<TestView> views; | |
1604 connection_->GetViewTree(BuildViewId(1, 1), &views); | |
1605 ASSERT_EQ(1u, views.size()); | |
1606 ASSERT_EQ(1u, views[0].properties.size()); | |
1607 EXPECT_EQ(one, views[0].properties["one"]); | |
1608 } | |
1609 | |
1610 // Set back to null. | |
1611 ASSERT_TRUE(connection_->SetViewProperty(BuildViewId(1, 1), "one", NULL)); | |
1612 { | |
1613 connection2_->DoRunLoopUntilChangesCount(1); | |
1614 ASSERT_EQ(1u, connection2_->changes().size()); | |
1615 EXPECT_EQ("PropertyChanged view=1,1 key=one value=NULL", | |
1616 ChangesToDescription1(connection2_->changes())[0]); | |
1617 } | |
1618 } | |
1619 | |
1620 // WARNING: this class is deprecated and will be replaced with | |
1621 // view_manager_server_apptest soonish. Add new tests there. | |
1622 | |
1623 } // namespace service | |
1624 } // namespace mojo | |
OLD | NEW |