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