Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / mojo / services / view_manager / view_manager_unittest.cc
blobc939489b586001612b7504e43b3058ddbd4131bf
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.
5 #include <string>
6 #include <vector>
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/public/cpp/application/application_connection.h"
19 #include "mojo/public/cpp/application/application_delegate.h"
20 #include "mojo/public/cpp/application/application_impl.h"
21 #include "mojo/public/cpp/application/connect.h"
22 #include "mojo/public/cpp/bindings/lib/router.h"
23 #include "mojo/public/interfaces/application/service_provider.mojom.h"
24 #include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
25 #include "mojo/services/public/cpp/view_manager/types.h"
26 #include "mojo/services/public/cpp/view_manager/util.h"
27 #include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h"
28 #include "mojo/services/view_manager/ids.h"
29 #include "mojo/services/view_manager/test_change_tracker.h"
30 #include "mojo/shell/shell_test_helper.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "ui/gfx/geometry/rect.h"
34 namespace mojo {
35 namespace service {
37 namespace {
39 const char kTestServiceURL[] = "mojo:test_url";
40 const char kTestServiceURL2[] = "mojo:test_url2";
42 // ViewManagerProxy is a proxy to an ViewManagerService. It handles invoking
43 // ViewManagerService functions on the right thread in a synchronous manner
44 // (each ViewManagerService cover function blocks until the response from the
45 // ViewManagerService is returned). In addition it tracks the set of
46 // ViewManagerClient messages received by way of a vector of Changes. Use
47 // DoRunLoopUntilChangesCount() to wait for a certain number of messages to be
48 // received.
49 class ViewManagerProxy : public TestChangeTracker::Delegate {
50 public:
51 explicit ViewManagerProxy(TestChangeTracker* tracker)
52 : tracker_(tracker),
53 main_loop_(NULL),
54 view_manager_(NULL),
55 quit_count_(0),
56 router_(NULL) {
57 SetInstance(this);
60 virtual ~ViewManagerProxy() {
63 // Runs a message loop until the single instance has been created.
64 static ViewManagerProxy* WaitForInstance() {
65 if (!instance_)
66 RunMainLoop();
67 ViewManagerProxy* instance = instance_;
68 instance_ = NULL;
69 return instance;
72 ViewManagerService* view_manager() { return view_manager_; }
74 // Runs the main loop until |count| changes have been received.
75 std::vector<Change> DoRunLoopUntilChangesCount(size_t count) {
76 DCHECK_EQ(0u, quit_count_);
77 if (tracker_->changes()->size() >= count) {
78 CopyChangesFromTracker();
79 return changes_;
81 quit_count_ = count - tracker_->changes()->size();
82 // Run the current message loop. When |count| Changes have been received,
83 // we'll quit.
84 RunMainLoop();
85 return changes_;
88 const std::vector<Change>& changes() const { return changes_; }
90 // Destroys the connection, blocking until done.
91 void Destroy() {
92 router_->CloseMessagePipe();
95 void ClearChanges() {
96 changes_.clear();
97 tracker_->changes()->clear();
100 void CopyChangesFromTracker() {
101 std::vector<Change> changes;
102 tracker_->changes()->swap(changes);
103 changes_.swap(changes);
106 // The following functions are cover methods for ViewManagerService. They
107 // block until the result is received.
108 bool CreateView(Id view_id) {
109 changes_.clear();
110 ErrorCode result = ERROR_CODE_NONE;
111 view_manager_->CreateView(
112 view_id,
113 base::Bind(&ViewManagerProxy::GotResultWithErrorCode,
114 base::Unretained(this),
115 &result));
116 RunMainLoop();
117 return result == ERROR_CODE_NONE;
119 ErrorCode CreateViewWithErrorCode(Id view_id) {
120 changes_.clear();
121 ErrorCode result = ERROR_CODE_NONE;
122 view_manager_->CreateView(
123 view_id,
124 base::Bind(&ViewManagerProxy::GotResultWithErrorCode,
125 base::Unretained(this),
126 &result));
127 RunMainLoop();
128 return result;
130 bool AddView(Id parent, Id child) {
131 changes_.clear();
132 bool result = false;
133 view_manager_->AddView(parent, child,
134 base::Bind(&ViewManagerProxy::GotResult,
135 base::Unretained(this), &result));
136 RunMainLoop();
137 return result;
139 bool RemoveViewFromParent(Id view_id) {
140 changes_.clear();
141 bool result = false;
142 view_manager_->RemoveViewFromParent(
143 view_id,
144 base::Bind(
145 &ViewManagerProxy::GotResult, base::Unretained(this), &result));
146 RunMainLoop();
147 return result;
149 bool ReorderView(Id view_id, Id relative_view_id, OrderDirection direction) {
150 changes_.clear();
151 bool result = false;
152 view_manager_->ReorderView(
153 view_id,
154 relative_view_id,
155 direction,
156 base::Bind(
157 &ViewManagerProxy::GotResult, base::Unretained(this), &result));
158 RunMainLoop();
159 return result;
161 void GetViewTree(Id view_id, std::vector<TestView>* views) {
162 changes_.clear();
163 view_manager_->GetViewTree(
164 view_id,
165 base::Bind(
166 &ViewManagerProxy::GotViewTree, base::Unretained(this), views));
167 RunMainLoop();
169 bool Embed(const Id view_id, const char* url) {
170 changes_.clear();
171 base::AutoReset<bool> auto_reset(&in_embed_, true);
172 bool result = false;
173 ServiceProviderPtr services;
174 view_manager_->Embed(
175 url,
176 view_id,
177 services.Pass(),
178 base::Bind(
179 &ViewManagerProxy::GotResult, base::Unretained(this), &result));
180 RunMainLoop();
181 return result;
183 bool DeleteView(Id view_id) {
184 changes_.clear();
185 bool result = false;
186 view_manager_->DeleteView(
187 view_id,
188 base::Bind(
189 &ViewManagerProxy::GotResult, base::Unretained(this), &result));
190 RunMainLoop();
191 return result;
193 bool SetViewBounds(Id view_id, const gfx::Rect& bounds) {
194 changes_.clear();
195 bool result = false;
196 view_manager_->SetViewBounds(
197 view_id,
198 Rect::From(bounds),
199 base::Bind(
200 &ViewManagerProxy::GotResult, base::Unretained(this), &result));
201 RunMainLoop();
202 return result;
205 private:
206 friend class TestViewManagerClientConnection;
208 void set_router(mojo::internal::Router* router) { router_ = router; }
210 void set_view_manager(ViewManagerService* view_manager) {
211 view_manager_ = view_manager;
214 static void RunMainLoop() {
215 DCHECK(!main_run_loop_);
216 main_run_loop_ = new base::RunLoop;
217 main_run_loop_->Run();
218 delete main_run_loop_;
219 main_run_loop_ = NULL;
222 void QuitCountReached() {
223 CopyChangesFromTracker();
224 main_run_loop_->Quit();
227 static void SetInstance(ViewManagerProxy* instance) {
228 DCHECK(!instance_);
229 instance_ = instance;
230 // Embed() runs its own run loop that is quit when the result is
231 // received. Embed() also results in a new instance. If we quit here while
232 // waiting for a Embed() we would prematurely return before we got the
233 // result from Embed().
234 if (!in_embed_ && main_run_loop_)
235 main_run_loop_->Quit();
238 // Callbacks from the various ViewManagerService functions.
239 void GotResult(bool* result_cache, bool result) {
240 *result_cache = result;
241 DCHECK(main_run_loop_);
242 main_run_loop_->Quit();
245 void GotResultWithErrorCode(ErrorCode* error_code_cache,
246 ErrorCode error_code) {
247 *error_code_cache = error_code;
248 DCHECK(main_run_loop_);
249 main_run_loop_->Quit();
252 void GotViewTree(std::vector<TestView>* views, Array<ViewDataPtr> results) {
253 ViewDatasToTestViews(results, views);
254 DCHECK(main_run_loop_);
255 main_run_loop_->Quit();
258 // TestChangeTracker::Delegate:
259 virtual void OnChangeAdded() OVERRIDE {
260 if (quit_count_ > 0 && --quit_count_ == 0)
261 QuitCountReached();
264 static ViewManagerProxy* instance_;
265 static base::RunLoop* main_run_loop_;
266 static bool in_embed_;
268 TestChangeTracker* tracker_;
270 // MessageLoop of the test.
271 base::MessageLoop* main_loop_;
273 ViewManagerService* view_manager_;
275 // Number of changes we're waiting on until we quit the current loop.
276 size_t quit_count_;
278 std::vector<Change> changes_;
280 mojo::internal::Router* router_;
282 DISALLOW_COPY_AND_ASSIGN(ViewManagerProxy);
285 // static
286 ViewManagerProxy* ViewManagerProxy::instance_ = NULL;
288 // static
289 base::RunLoop* ViewManagerProxy::main_run_loop_ = NULL;
291 // static
292 bool ViewManagerProxy::in_embed_ = false;
294 class TestViewManagerClientConnection
295 : public InterfaceImpl<ViewManagerClient> {
296 public:
297 TestViewManagerClientConnection() : connection_(&tracker_) {
298 tracker_.set_delegate(&connection_);
301 // InterfaceImpl:
302 virtual void OnConnectionEstablished() OVERRIDE {
303 connection_.set_router(internal_state()->router());
304 connection_.set_view_manager(client());
307 // ViewManagerClient:
308 virtual void OnEmbed(
309 ConnectionSpecificId connection_id,
310 const String& creator_url,
311 ViewDataPtr root,
312 InterfaceRequest<ServiceProvider> services) OVERRIDE {
313 tracker_.OnEmbed(connection_id, creator_url, root.Pass());
315 virtual void OnViewBoundsChanged(Id view_id,
316 RectPtr old_bounds,
317 RectPtr new_bounds) OVERRIDE {
318 tracker_.OnViewBoundsChanged(view_id, old_bounds.Pass(), new_bounds.Pass());
320 virtual void OnViewHierarchyChanged(Id view,
321 Id new_parent,
322 Id old_parent,
323 Array<ViewDataPtr> views) OVERRIDE {
324 tracker_.OnViewHierarchyChanged(view, new_parent, old_parent, views.Pass());
326 virtual void OnViewReordered(Id view_id,
327 Id relative_view_id,
328 OrderDirection direction) OVERRIDE {
329 tracker_.OnViewReordered(view_id, relative_view_id, direction);
331 virtual void OnViewDeleted(Id view) OVERRIDE { tracker_.OnViewDeleted(view); }
332 virtual void OnViewInputEvent(Id view_id,
333 EventPtr event,
334 const Callback<void()>& callback) OVERRIDE {
335 tracker_.OnViewInputEvent(view_id, event.Pass());
337 virtual void Embed(
338 const String& url,
339 InterfaceRequest<ServiceProvider> service_provider) OVERRIDE {
340 tracker_.DelegateEmbed(url);
342 virtual void DispatchOnViewInputEvent(mojo::EventPtr event) OVERRIDE {
345 private:
346 TestChangeTracker tracker_;
347 ViewManagerProxy connection_;
349 DISALLOW_COPY_AND_ASSIGN(TestViewManagerClientConnection);
352 // Used with ViewManagerService::Embed(). Creates a
353 // TestViewManagerClientConnection, which creates and owns the ViewManagerProxy.
354 class EmbedApplicationLoader : public ApplicationLoader,
355 ApplicationDelegate,
356 public InterfaceFactory<ViewManagerClient> {
357 public:
358 EmbedApplicationLoader() {}
359 virtual ~EmbedApplicationLoader() {}
361 // ApplicationLoader implementation:
362 virtual void Load(ApplicationManager* manager,
363 const GURL& url,
364 scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
365 ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
366 if (!shell_handle.is_valid())
367 return;
368 scoped_ptr<ApplicationImpl> app(new ApplicationImpl(this,
369 shell_handle.Pass()));
370 apps_.push_back(app.release());
372 virtual void OnApplicationError(ApplicationManager* manager,
373 const GURL& url) OVERRIDE {}
375 // ApplicationDelegate implementation:
376 virtual bool ConfigureIncomingConnection(ApplicationConnection* connection)
377 OVERRIDE {
378 connection->AddService(this);
379 return true;
382 // InterfaceFactory<ViewManagerClient> implementation:
383 virtual void Create(ApplicationConnection* connection,
384 InterfaceRequest<ViewManagerClient> request) OVERRIDE {
385 BindToRequest(new TestViewManagerClientConnection, &request);
388 private:
389 ScopedVector<ApplicationImpl> apps_;
391 DISALLOW_COPY_AND_ASSIGN(EmbedApplicationLoader);
394 // Creates an id used for transport from the specified parameters.
395 Id BuildViewId(ConnectionSpecificId connection_id,
396 ConnectionSpecificId view_id) {
397 return (connection_id << 16) | view_id;
400 // Callback from Embed(). |result| is the result of the
401 // Embed() call and |run_loop| the nested RunLoop.
402 void EmbedCallback(bool* result_cache, base::RunLoop* run_loop, bool result) {
403 *result_cache = result;
404 run_loop->Quit();
407 // Embed from an application that does not yet have a view manager connection.
408 // Blocks until result is determined.
409 bool InitEmbed(ViewManagerInitService* view_manager_init,
410 const std::string& url,
411 size_t number_of_calls) {
412 bool result = false;
413 base::RunLoop run_loop;
414 for (size_t i = 0; i < number_of_calls; ++i) {
415 ServiceProviderPtr sp;
416 view_manager_init->Embed(url, sp.Pass(),
417 base::Bind(&EmbedCallback, &result, &run_loop));
419 run_loop.Run();
420 return result;
423 } // namespace
425 typedef std::vector<std::string> Changes;
427 class ViewManagerTest : public testing::Test {
428 public:
429 ViewManagerTest()
430 : connection_(NULL),
431 connection2_(NULL),
432 connection3_(NULL) {}
434 virtual void SetUp() OVERRIDE {
435 test_helper_.Init();
437 test_helper_.SetLoaderForURL(
438 scoped_ptr<ApplicationLoader>(new EmbedApplicationLoader()),
439 GURL(kTestServiceURL));
441 test_helper_.SetLoaderForURL(
442 scoped_ptr<ApplicationLoader>(new EmbedApplicationLoader()),
443 GURL(kTestServiceURL2));
445 test_helper_.application_manager()->ConnectToService(
446 GURL("mojo:mojo_view_manager"), &view_manager_init_);
447 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), kTestServiceURL, 1));
449 connection_ = ViewManagerProxy::WaitForInstance();
450 ASSERT_TRUE(connection_ != NULL);
451 connection_->DoRunLoopUntilChangesCount(1);
454 virtual void TearDown() OVERRIDE {
455 if (connection3_)
456 connection3_->Destroy();
457 if (connection2_)
458 connection2_->Destroy();
459 if (connection_)
460 connection_->Destroy();
463 protected:
464 void EstablishSecondConnectionWithRoot(Id root_id) {
465 ASSERT_TRUE(connection_->Embed(root_id, kTestServiceURL));
466 connection2_ = ViewManagerProxy::WaitForInstance();
467 ASSERT_TRUE(connection2_ != NULL);
468 connection2_->DoRunLoopUntilChangesCount(1);
469 ASSERT_EQ(1u, connection2_->changes().size());
472 // Creates a second connection to the viewmanager.
473 void EstablishSecondConnection(bool create_initial_view) {
474 if (create_initial_view)
475 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
476 ASSERT_NO_FATAL_FAILURE(
477 EstablishSecondConnectionWithRoot(BuildViewId(1, 1)));
478 const std::vector<Change>& changes(connection2_->changes());
479 ASSERT_EQ(1u, changes.size());
480 EXPECT_EQ("OnEmbed creator=mojo:test_url",
481 ChangesToDescription1(changes)[0]);
482 if (create_initial_view) {
483 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes));
487 void EstablishThirdConnection(ViewManagerProxy* owner, Id root_id) {
488 ASSERT_TRUE(connection3_ == NULL);
489 ASSERT_TRUE(owner->Embed(root_id, kTestServiceURL2));
490 connection3_ = ViewManagerProxy::WaitForInstance();
491 ASSERT_TRUE(connection3_ != NULL);
492 connection3_->DoRunLoopUntilChangesCount(1);
493 ASSERT_EQ(1u, connection3_->changes().size());
494 EXPECT_EQ("OnEmbed creator=mojo:test_url",
495 ChangesToDescription1(connection3_->changes())[0]);
498 void DestroySecondConnection() {
499 connection2_->Destroy();
500 connection2_ = NULL;
503 base::ShadowingAtExitManager at_exit_;
504 shell::ShellTestHelper test_helper_;
506 ViewManagerInitServicePtr view_manager_init_;
508 // NOTE: this connection is the root. As such, it has special permissions.
509 ViewManagerProxy* connection_;
510 ViewManagerProxy* connection2_;
511 ViewManagerProxy* connection3_;
513 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
516 TEST_F(ViewManagerTest, SecondEmbedRoot_InitService) {
517 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), kTestServiceURL, 1));
518 connection_->DoRunLoopUntilChangesCount(1);
519 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url);
522 TEST_F(ViewManagerTest, SecondEmbedRoot_Service) {
523 ASSERT_TRUE(connection_->Embed(BuildViewId(0, 0), kTestServiceURL));
524 connection_->DoRunLoopUntilChangesCount(1);
525 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url);
528 TEST_F(ViewManagerTest, MultipleEmbedRootsBeforeWTHReady) {
529 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), kTestServiceURL, 2));
530 connection_->DoRunLoopUntilChangesCount(2);
531 EXPECT_EQ(kTestServiceURL, connection_->changes()[0].embed_url);
532 EXPECT_EQ(kTestServiceURL, connection_->changes()[1].embed_url);
535 // Verifies client gets a valid id.
536 #if defined(OS_LINUX)
537 // http://crbug.com/396492
538 #define MAYBE_ValidId DISABLED_ValidId
539 #else
540 #define MAYBE_ValidId ValidId
541 #endif
542 TEST_F(ViewManagerTest, MAYBE_ValidId) {
543 // TODO(beng): this should really have the URL of the application that
544 // connected to ViewManagerInit.
545 EXPECT_EQ("OnEmbed creator=",
546 ChangesToDescription1(connection_->changes())[0]);
548 // All these tests assume 1 for the client id. The only real assertion here is
549 // the client id is not zero, but adding this as rest of code here assumes 1.
550 EXPECT_EQ(1, connection_->changes()[0].connection_id);
553 // Verifies two clients/connections get different ids.
554 TEST_F(ViewManagerTest, TwoClientsGetDifferentConnectionIds) {
555 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
556 EXPECT_EQ("OnEmbed creator=mojo:test_url",
557 ChangesToDescription1(connection2_->changes())[0]);
559 // It isn't strictly necessary that the second connection gets 2, but these
560 // tests are written assuming that is the case. The key thing is the
561 // connection ids of |connection_| and |connection2_| differ.
562 EXPECT_EQ(2, connection2_->changes()[0].connection_id);
565 // Verifies when Embed() is invoked any child views are removed.
566 TEST_F(ViewManagerTest, ViewsRemovedWhenEmbedding) {
567 // Two views 1 and 2. 2 is parented to 1.
568 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
569 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
570 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2)));
572 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
573 EXPECT_EQ("[view=1,1 parent=null]",
574 ChangeViewDescription(connection2_->changes()));
576 // Embed() removed view 2.
578 std::vector<TestView> views;
579 connection_->GetViewTree(BuildViewId(1, 2), &views);
580 ASSERT_EQ(1u, views.size());
581 EXPECT_EQ("view=1,2 parent=null", views[0].ToString());
584 // |connection2_| should not see view 2.
586 std::vector<TestView> views;
587 connection2_->GetViewTree(BuildViewId(1, 1), &views);
588 ASSERT_EQ(1u, views.size());
589 EXPECT_EQ("view=1,1 parent=null", views[0].ToString());
592 std::vector<TestView> views;
593 connection2_->GetViewTree(BuildViewId(1, 2), &views);
594 EXPECT_TRUE(views.empty());
597 // Views 3 and 4 in connection 2.
598 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3)));
599 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 4)));
600 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 3), BuildViewId(2, 4)));
602 // Connection 3 rooted at 2.
603 ASSERT_NO_FATAL_FAILURE(
604 EstablishThirdConnection(connection2_, BuildViewId(2, 3)));
606 // View 4 should no longer have a parent.
608 std::vector<TestView> views;
609 connection2_->GetViewTree(BuildViewId(2, 3), &views);
610 ASSERT_EQ(1u, views.size());
611 EXPECT_EQ("view=2,3 parent=null", views[0].ToString());
613 views.clear();
614 connection2_->GetViewTree(BuildViewId(2, 4), &views);
615 ASSERT_EQ(1u, views.size());
616 EXPECT_EQ("view=2,4 parent=null", views[0].ToString());
619 // And view 4 should not be visible to connection 3.
621 std::vector<TestView> views;
622 connection3_->GetViewTree(BuildViewId(2, 3), &views);
623 ASSERT_EQ(1u, views.size());
624 EXPECT_EQ("view=2,3 parent=null", views[0].ToString());
628 // Verifies once Embed() has been invoked the parent connection can't see any
629 // children.
630 TEST_F(ViewManagerTest, CantAccessChildrenOfEmbeddedView) {
631 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
633 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
634 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
636 ASSERT_NO_FATAL_FAILURE(
637 EstablishThirdConnection(connection2_, BuildViewId(2, 2)));
639 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 3)));
640 ASSERT_TRUE(connection3_->AddView(BuildViewId(2, 2), BuildViewId(3, 3)));
642 // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a
643 // different connection.
645 std::vector<TestView> views;
646 connection2_->GetViewTree(BuildViewId(2, 2), &views);
647 ASSERT_EQ(1u, views.size());
648 EXPECT_EQ("view=2,2 parent=1,1", views[0].ToString());
652 std::vector<TestView> views;
653 connection2_->GetViewTree(BuildViewId(3, 3), &views);
654 EXPECT_TRUE(views.empty());
657 // Connection 2 shouldn't be able to get view 3 at all.
659 std::vector<TestView> views;
660 connection2_->GetViewTree(BuildViewId(3, 3), &views);
661 EXPECT_TRUE(views.empty());
664 // Connection 1 should be able to see it all (its the root).
666 std::vector<TestView> views;
667 connection_->GetViewTree(BuildViewId(1, 1), &views);
668 ASSERT_EQ(3u, views.size());
669 EXPECT_EQ("view=1,1 parent=null", views[0].ToString());
670 EXPECT_EQ("view=2,2 parent=1,1", views[1].ToString());
671 EXPECT_EQ("view=3,3 parent=2,2", views[2].ToString());
675 // Verifies once Embed() has been invoked the parent can't mutate the children.
676 TEST_F(ViewManagerTest, CantModifyChildrenOfEmbeddedView) {
677 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
679 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
680 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
682 ASSERT_NO_FATAL_FAILURE(
683 EstablishThirdConnection(connection2_, BuildViewId(2, 2)));
685 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3)));
686 // Connection 2 shouldn't be able to add anything to the view anymore.
687 ASSERT_FALSE(connection2_->AddView(BuildViewId(2, 2), BuildViewId(2, 3)));
689 // Create view 3 in connection 3 and add it to view 3.
690 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 3)));
691 ASSERT_TRUE(connection3_->AddView(BuildViewId(2, 2), BuildViewId(3, 3)));
693 // Connection 2 shouldn't be able to remove view 3.
694 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(3, 3)));
697 // Verifies client gets a valid id.
698 TEST_F(ViewManagerTest, CreateView) {
699 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
700 EXPECT_TRUE(connection_->changes().empty());
702 // Can't create a view with the same id.
703 ASSERT_EQ(ERROR_CODE_VALUE_IN_USE,
704 connection_->CreateViewWithErrorCode(BuildViewId(1, 1)));
705 EXPECT_TRUE(connection_->changes().empty());
707 // Can't create a view with a bogus connection id.
708 EXPECT_EQ(ERROR_CODE_ILLEGAL_ARGUMENT,
709 connection_->CreateViewWithErrorCode(BuildViewId(2, 1)));
710 EXPECT_TRUE(connection_->changes().empty());
713 // Verifies AddView fails when view is already in position.
714 TEST_F(ViewManagerTest, AddViewWithNoChange) {
715 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
716 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3)));
718 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
720 // Make 3 a child of 2.
721 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3)));
723 // Try again, this should fail.
724 EXPECT_FALSE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3)));
727 // Verifies AddView fails when view is already in position.
728 TEST_F(ViewManagerTest, AddAncestorFails) {
729 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
730 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3)));
732 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
734 // Make 3 a child of 2.
735 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 3)));
737 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
738 EXPECT_FALSE(connection_->AddView(BuildViewId(1, 3), BuildViewId(1, 2)));
741 // Verifies adding to root sends right notifications.
742 TEST_F(ViewManagerTest, AddToRoot) {
743 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 21)));
744 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 3)));
746 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
748 // Make 3 a child of 21.
749 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 21), BuildViewId(1, 3)));
751 // Make 21 a child of 1.
752 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 21)));
754 // Connection 2 should not be told anything (because the view is from a
755 // different connection). Create a view to ensure we got a response from
756 // the server.
757 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 100)));
758 connection2_->CopyChangesFromTracker();
759 EXPECT_TRUE(connection2_->changes().empty());
762 // Verifies HierarchyChanged is correctly sent for various adds/removes.
763 TEST_F(ViewManagerTest, ViewHierarchyChangedViews) {
764 // 1,2->1,11.
765 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
766 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 11)));
767 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 2), BuildViewId(1, 11)));
769 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
771 // 1,1->1,2->1,11
773 // Client 2 should not get anything (1,2 is from another connection).
774 connection2_->ClearChanges();
775 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 2)));
776 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 100)));
777 connection2_->CopyChangesFromTracker();
778 EXPECT_TRUE(connection2_->changes().empty());
781 // 0,1->1,1->1,2->1,11.
783 // Again, client 2 should not get anything.
784 connection2_->ClearChanges();
785 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
786 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 101)));
787 connection2_->CopyChangesFromTracker();
788 EXPECT_TRUE(connection2_->changes().empty());
791 // 1,1->1,2->1,11.
793 connection2_->ClearChanges();
794 ASSERT_TRUE(connection_->RemoveViewFromParent(BuildViewId(1, 1)));
795 EXPECT_TRUE(connection_->changes().empty());
796 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 102)));
797 connection2_->CopyChangesFromTracker();
798 EXPECT_TRUE(connection2_->changes().empty());
801 // 1,1->1,2->1,11->1,111.
802 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 111)));
804 connection2_->ClearChanges();
805 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 11), BuildViewId(1, 111)));
806 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 103)));
807 connection2_->CopyChangesFromTracker();
808 EXPECT_TRUE(connection2_->changes().empty());
811 // 0,1->1,1->1,2->1,11->1,111
813 connection2_->ClearChanges();
814 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
815 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 104)));
816 connection2_->CopyChangesFromTracker();
817 EXPECT_TRUE(connection2_->changes().empty());
821 TEST_F(ViewManagerTest, ViewHierarchyChangedAddingKnownToUnknown) {
822 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no
823 // parent).
824 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
826 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 11)));
827 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
828 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 21)));
830 // Set up the hierarchy.
831 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
832 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 11)));
833 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 2), BuildViewId(2, 21)));
835 // Remove 11, should result in a hierarchy change for the root.
837 connection_->ClearChanges();
838 ASSERT_TRUE(connection2_->RemoveViewFromParent(BuildViewId(2, 11)));
840 connection_->DoRunLoopUntilChangesCount(1);
841 const Changes changes(ChangesToDescription1(connection_->changes()));
842 ASSERT_EQ(1u, changes.size());
843 EXPECT_EQ("HierarchyChanged view=2,11 new_parent=null old_parent=1,1",
844 changes[0]);
847 // Add 2 to 1.
849 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
851 connection_->DoRunLoopUntilChangesCount(1);
852 const Changes changes(ChangesToDescription1(connection_->changes()));
853 ASSERT_EQ(1u, changes.size());
854 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
855 changes[0]);
856 EXPECT_EQ(
857 "[view=2,2 parent=1,1],"
858 "[view=2,21 parent=2,2]",
859 ChangeViewDescription(connection_->changes()));
863 TEST_F(ViewManagerTest, ReorderView) {
864 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
866 Id view1_id = BuildViewId(2, 1);
867 Id view2_id = BuildViewId(2, 2);
868 Id view3_id = BuildViewId(2, 3);
869 Id view4_id = BuildViewId(1, 4); // Peer to 1,1
870 Id view5_id = BuildViewId(1, 5); // Peer to 1,1
871 Id view6_id = BuildViewId(2, 6); // Child of 1,2.
872 Id view7_id = BuildViewId(2, 7); // Unparented.
873 Id view8_id = BuildViewId(2, 8); // Unparented.
874 ASSERT_TRUE(connection2_->CreateView(view1_id));
875 ASSERT_TRUE(connection2_->CreateView(view2_id));
876 ASSERT_TRUE(connection2_->CreateView(view3_id));
877 ASSERT_TRUE(connection_->CreateView(view4_id));
878 ASSERT_TRUE(connection_->CreateView(view5_id));
879 ASSERT_TRUE(connection2_->CreateView(view6_id));
880 ASSERT_TRUE(connection2_->CreateView(view7_id));
881 ASSERT_TRUE(connection2_->CreateView(view8_id));
882 ASSERT_TRUE(connection2_->AddView(view1_id, view2_id));
883 ASSERT_TRUE(connection2_->AddView(view2_id, view6_id));
884 ASSERT_TRUE(connection2_->AddView(view1_id, view3_id));
885 ASSERT_TRUE(
886 connection_->AddView(ViewIdToTransportId(RootViewId()), view4_id));
887 ASSERT_TRUE(
888 connection_->AddView(ViewIdToTransportId(RootViewId()), view5_id));
890 ASSERT_TRUE(
891 connection_->AddView(ViewIdToTransportId(RootViewId()), view1_id));
894 ASSERT_TRUE(
895 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_ABOVE));
897 connection_->DoRunLoopUntilChangesCount(1);
898 const Changes changes(ChangesToDescription1(connection_->changes()));
899 ASSERT_EQ(1u, changes.size());
900 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=above", changes[0]);
904 ASSERT_TRUE(
905 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_BELOW));
907 connection_->DoRunLoopUntilChangesCount(1);
908 const Changes changes(ChangesToDescription1(connection_->changes()));
909 ASSERT_EQ(1u, changes.size());
910 EXPECT_EQ("Reordered view=2,2 relative=2,3 direction=below", changes[0]);
913 // view2 is already below view3.
914 EXPECT_FALSE(
915 connection2_->ReorderView(view2_id, view3_id, ORDER_DIRECTION_BELOW));
917 // view4 & 5 are unknown to connection2_.
918 EXPECT_FALSE(
919 connection2_->ReorderView(view4_id, view5_id, ORDER_DIRECTION_ABOVE));
921 // view6 & view3 have different parents.
922 EXPECT_FALSE(
923 connection_->ReorderView(view3_id, view6_id, ORDER_DIRECTION_ABOVE));
925 // Non-existent view-ids
926 EXPECT_FALSE(connection_->ReorderView(
927 BuildViewId(1, 27), BuildViewId(1, 28), ORDER_DIRECTION_ABOVE));
929 // view7 & view8 are un-parented.
930 EXPECT_FALSE(
931 connection_->ReorderView(view7_id, view8_id, ORDER_DIRECTION_ABOVE));
934 // Verifies DeleteView works.
935 TEST_F(ViewManagerTest, DeleteView) {
936 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
937 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
939 // Make 2 a child of 1.
941 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
942 connection_->DoRunLoopUntilChangesCount(1);
943 const Changes changes(ChangesToDescription1(connection_->changes()));
944 ASSERT_EQ(1u, changes.size());
945 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
946 changes[0]);
949 // Delete 2.
951 ASSERT_TRUE(connection2_->DeleteView(BuildViewId(2, 2)));
952 EXPECT_TRUE(connection2_->changes().empty());
954 connection_->DoRunLoopUntilChangesCount(1);
955 const Changes changes(ChangesToDescription1(connection_->changes()));
956 ASSERT_EQ(1u, changes.size());
957 EXPECT_EQ("ViewDeleted view=2,2", changes[0]);
961 // Verifies DeleteView isn't allowed from a separate connection.
962 TEST_F(ViewManagerTest, DeleteViewFromAnotherConnectionDisallowed) {
963 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
964 EXPECT_FALSE(connection2_->DeleteView(BuildViewId(1, 1)));
967 // Verifies if a view was deleted and then reused that other clients are
968 // properly notified.
969 TEST_F(ViewManagerTest, ReuseDeletedViewId) {
970 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
971 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
973 // Add 2 to 1.
975 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
977 connection_->DoRunLoopUntilChangesCount(1);
978 const Changes changes(ChangesToDescription1(connection_->changes()));
979 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
980 changes[0]);
981 EXPECT_EQ("[view=2,2 parent=1,1]",
982 ChangeViewDescription(connection_->changes()));
985 // Delete 2.
987 ASSERT_TRUE(connection2_->DeleteView(BuildViewId(2, 2)));
989 connection_->DoRunLoopUntilChangesCount(1);
990 const Changes changes(ChangesToDescription1(connection_->changes()));
991 ASSERT_EQ(1u, changes.size());
992 EXPECT_EQ("ViewDeleted view=2,2", changes[0]);
995 // Create 2 again, and add it back to 1. Should get the same notification.
996 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
998 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
1000 connection_->DoRunLoopUntilChangesCount(1);
1001 const Changes changes(ChangesToDescription1(connection_->changes()));
1002 EXPECT_EQ("HierarchyChanged view=2,2 new_parent=1,1 old_parent=null",
1003 changes[0]);
1004 EXPECT_EQ("[view=2,2 parent=1,1]",
1005 ChangeViewDescription(connection_->changes()));
1009 // Assertions for GetViewTree.
1010 TEST_F(ViewManagerTest, GetViewTree) {
1011 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1013 // Create 11 in first connection and make it a child of 1.
1014 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 11)));
1015 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1016 ASSERT_TRUE(connection_->AddView(BuildViewId(1, 1), BuildViewId(1, 11)));
1018 // Create two views in second connection, 2 and 3, both children of 1.
1019 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 2)));
1020 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 3)));
1021 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 2)));
1022 ASSERT_TRUE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(2, 3)));
1024 // Verifies GetViewTree() on the root. The root connection sees all.
1026 std::vector<TestView> views;
1027 connection_->GetViewTree(BuildViewId(0, 1), &views);
1028 ASSERT_EQ(5u, views.size());
1029 EXPECT_EQ("view=0,1 parent=null", views[0].ToString());
1030 EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString());
1031 EXPECT_EQ("view=1,11 parent=1,1", views[2].ToString());
1032 EXPECT_EQ("view=2,2 parent=1,1", views[3].ToString());
1033 EXPECT_EQ("view=2,3 parent=1,1", views[4].ToString());
1036 // Verifies GetViewTree() on the view 1,1. This does not include any children
1037 // as they are not from this connection.
1039 std::vector<TestView> views;
1040 connection2_->GetViewTree(BuildViewId(1, 1), &views);
1041 ASSERT_EQ(1u, views.size());
1042 EXPECT_EQ("view=1,1 parent=null", views[0].ToString());
1045 // Connection 2 shouldn't be able to get the root tree.
1047 std::vector<TestView> views;
1048 connection2_->GetViewTree(BuildViewId(0, 1), &views);
1049 ASSERT_EQ(0u, views.size());
1053 TEST_F(ViewManagerTest, SetViewBounds) {
1054 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
1055 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1057 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1059 ASSERT_TRUE(
1060 connection_->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 100, 100)));
1062 connection2_->DoRunLoopUntilChangesCount(1);
1063 const Changes changes(ChangesToDescription1(connection2_->changes()));
1064 ASSERT_EQ(1u, changes.size());
1065 EXPECT_EQ("BoundsChanged view=1,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100",
1066 changes[0]);
1068 // Should not be possible to change the bounds of a view created by another
1069 // connection.
1070 ASSERT_FALSE(
1071 connection2_->SetViewBounds(BuildViewId(1, 1), gfx::Rect(0, 0, 0, 0)));
1074 // Verify AddView fails when trying to manipulate views in other roots.
1075 TEST_F(ViewManagerTest, CantMoveViewsFromOtherRoot) {
1076 // Create 1 and 2 in the first connection.
1077 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
1078 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
1080 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1082 // Try to move 2 to be a child of 1 from connection 2. This should fail as 2
1083 // should not be able to access 1.
1084 ASSERT_FALSE(connection2_->AddView(BuildViewId(1, 1), BuildViewId(1, 2)));
1086 // Try to reparent 1 to the root. A connection is not allowed to reparent its
1087 // roots.
1088 ASSERT_FALSE(connection2_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1091 // Verify RemoveViewFromParent fails for views that are descendants of the
1092 // roots.
1093 TEST_F(ViewManagerTest, CantRemoveViewsInOtherRoots) {
1094 // Create 1 and 2 in the first connection and parent both to the root.
1095 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
1096 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
1098 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1099 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 2)));
1101 // Establish the second connection and give it the root 1.
1102 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1104 // Connection 2 should not be able to remove view 2 or 1 from its parent.
1105 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(1, 2)));
1106 ASSERT_FALSE(connection2_->RemoveViewFromParent(BuildViewId(1, 1)));
1108 // Create views 10 and 11 in 2.
1109 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 10)));
1110 ASSERT_TRUE(connection2_->CreateView(BuildViewId(2, 11)));
1112 // Parent 11 to 10.
1113 ASSERT_TRUE(connection2_->AddView(BuildViewId(2, 10), BuildViewId(2, 11)));
1114 // Remove 11 from 10.
1115 ASSERT_TRUE(connection2_->RemoveViewFromParent(BuildViewId(2, 11)));
1117 // Verify nothing was actually removed.
1119 std::vector<TestView> views;
1120 connection_->GetViewTree(BuildViewId(0, 1), &views);
1121 ASSERT_EQ(3u, views.size());
1122 EXPECT_EQ("view=0,1 parent=null", views[0].ToString());
1123 EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString());
1124 EXPECT_EQ("view=1,2 parent=0,1", views[2].ToString());
1128 // Verify GetViewTree fails for views that are not descendants of the roots.
1129 TEST_F(ViewManagerTest, CantGetViewTreeOfOtherRoots) {
1130 // Create 1 and 2 in the first connection and parent both to the root.
1131 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
1132 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
1134 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 1)));
1135 ASSERT_TRUE(connection_->AddView(BuildViewId(0, 1), BuildViewId(1, 2)));
1137 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1139 std::vector<TestView> views;
1141 // Should get nothing for the root.
1142 connection2_->GetViewTree(BuildViewId(0, 1), &views);
1143 ASSERT_TRUE(views.empty());
1145 // Should get nothing for view 2.
1146 connection2_->GetViewTree(BuildViewId(1, 2), &views);
1147 ASSERT_TRUE(views.empty());
1149 // Should get view 1 if asked for.
1150 connection2_->GetViewTree(BuildViewId(1, 1), &views);
1151 ASSERT_EQ(1u, views.size());
1152 EXPECT_EQ("view=1,1 parent=null", views[0].ToString());
1155 TEST_F(ViewManagerTest, ConnectTwice) {
1156 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
1157 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 2)));
1159 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1161 // Try to connect again to 1,1, this should fail as already connected to that
1162 // root.
1163 ASSERT_FALSE(connection_->Embed(BuildViewId(1, 1), kTestServiceURL));
1165 // Connecting to 1,2 should succeed and end up in connection2.
1167 ASSERT_TRUE(connection_->Embed(BuildViewId(1, 2), kTestServiceURL));
1168 connection2_->DoRunLoopUntilChangesCount(1);
1169 const Changes changes(ChangesToDescription1(connection2_->changes()));
1170 ASSERT_EQ(1u, changes.size());
1171 EXPECT_EQ("OnEmbed creator=mojo:test_url", changes[0]);
1172 EXPECT_EQ("[view=1,2 parent=null]",
1173 ChangeViewDescription(connection2_->changes()));
1177 TEST_F(ViewManagerTest, OnViewInput) {
1178 ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 1)));
1179 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1181 // Dispatch an event to the view and verify its received.
1183 EventPtr event(Event::New());
1184 event->action = static_cast<EventType>(1);
1185 connection_->view_manager()->DispatchOnViewInputEvent(BuildViewId(1, 1),
1186 event.Pass());
1187 connection2_->DoRunLoopUntilChangesCount(1);
1188 const Changes changes(ChangesToDescription1(connection2_->changes()));
1189 ASSERT_EQ(1u, changes.size());
1190 EXPECT_EQ("InputEvent view=1,1 event_action=1", changes[0]);
1194 TEST_F(ViewManagerTest, EmbedWithSameViewId) {
1195 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1197 ASSERT_NO_FATAL_FAILURE(
1198 EstablishThirdConnection(connection_, BuildViewId(1, 1)));
1200 // Connection2 should have been told the view was deleted.
1202 connection2_->DoRunLoopUntilChangesCount(1);
1203 const Changes changes(ChangesToDescription1(connection2_->changes()));
1204 ASSERT_EQ(1u, changes.size());
1205 EXPECT_EQ("ViewDeleted view=1,1", changes[0]);
1208 // Connection2 has no root. Verify it can't see view 1,1 anymore.
1210 std::vector<TestView> views;
1211 connection2_->GetViewTree(BuildViewId(1, 1), &views);
1212 EXPECT_TRUE(views.empty());
1216 TEST_F(ViewManagerTest, EmbedWithSameViewId2) {
1217 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1219 ASSERT_NO_FATAL_FAILURE(
1220 EstablishThirdConnection(connection_, BuildViewId(1, 1)));
1222 // Connection2 should have been told the view was deleted.
1223 connection2_->DoRunLoopUntilChangesCount(1);
1224 connection2_->ClearChanges();
1226 // Create a view in the third connection and parent it to the root.
1227 ASSERT_TRUE(connection3_->CreateView(BuildViewId(3, 1)));
1228 ASSERT_TRUE(connection3_->AddView(BuildViewId(1, 1), BuildViewId(3, 1)));
1230 // Connection 1 should have been told about the add (it owns the view).
1232 connection_->DoRunLoopUntilChangesCount(1);
1233 const Changes changes(ChangesToDescription1(connection_->changes()));
1234 ASSERT_EQ(1u, changes.size());
1235 EXPECT_EQ("HierarchyChanged view=3,1 new_parent=1,1 old_parent=null",
1236 changes[0]);
1239 // Embed 1,1 back in connection 2.
1241 // 2 should be told about the new embed.
1242 ASSERT_TRUE(connection_->Embed(BuildViewId(1, 1), kTestServiceURL));
1243 connection2_->DoRunLoopUntilChangesCount(1);
1244 const std::vector<Change>& changes(connection2_->changes());
1245 ASSERT_EQ(1u, changes.size());
1246 EXPECT_EQ("OnEmbed creator=mojo:test_url",
1247 ChangesToDescription1(changes)[0]);
1248 EXPECT_EQ("[view=1,1 parent=null]", ChangeViewDescription(changes));
1250 // And 3 should get a delete.
1251 connection3_->DoRunLoopUntilChangesCount(1);
1252 ASSERT_EQ(1u, connection3_->changes().size());
1253 EXPECT_EQ("ViewDeleted view=1,1",
1254 ChangesToDescription1(connection3_->changes())[0]);
1257 // Connection3_ has no root. Verify it can't see view 1,1 anymore.
1259 std::vector<TestView> views;
1260 connection3_->GetViewTree(BuildViewId(1, 1), &views);
1261 EXPECT_TRUE(views.empty());
1264 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as
1265 // connection3_ can no longer see 1,1.
1267 std::vector<TestView> views;
1268 connection_->GetViewTree(BuildViewId(1, 1), &views);
1269 ASSERT_EQ(1u, views.size());
1270 EXPECT_EQ("view=1,1 parent=null", views[0].ToString());
1273 // Verify connection3_ can still see the view it created 3,1.
1275 std::vector<TestView> views;
1276 connection3_->GetViewTree(BuildViewId(3, 1), &views);
1277 ASSERT_EQ(1u, views.size());
1278 EXPECT_EQ("view=3,1 parent=null", views[0].ToString());
1282 // TODO(sky): add coverage of test that destroys connections and ensures other
1283 // connections get deletion notification.
1285 // TODO(sky): need to better track changes to initial connection. For example,
1286 // that SetBounsdViews/AddView and the like don't result in messages to the
1287 // originating connection.
1289 } // namespace service
1290 } // namespace mojo