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

Side by Side Diff: mojo/services/view_manager/view_manager_unittest.cc

Issue 774473003: Move view_manager service implementation to //services (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698