| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 #include <stdint.h> | 6 #include <stdint.h> |
| 7 | 7 |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 } | 106 } |
| 107 | 107 |
| 108 std::string WindowParentToString(Id window, Id parent) { | 108 std::string WindowParentToString(Id window, Id parent) { |
| 109 return base::StringPrintf("window=%s parent=%s", IdToString(window).c_str(), | 109 return base::StringPrintf("window=%s parent=%s", IdToString(window).c_str(), |
| 110 IdToString(parent).c_str()); | 110 IdToString(parent).c_str()); |
| 111 } | 111 } |
| 112 | 112 |
| 113 // ----------------------------------------------------------------------------- | 113 // ----------------------------------------------------------------------------- |
| 114 | 114 |
| 115 // A WindowTreeClient implementation that logs all changes to a tracker. | 115 // A WindowTreeClient implementation that logs all changes to a tracker. |
| 116 class TestWindowTreeClientImpl : public mojom::WindowTreeClient, | 116 class TestWindowTreeClient : public mojom::WindowTreeClient, |
| 117 public TestChangeTracker::Delegate, | 117 public TestChangeTracker::Delegate, |
| 118 public mojom::WindowManager { | 118 public mojom::WindowManager { |
| 119 public: | 119 public: |
| 120 TestWindowTreeClientImpl() | 120 TestWindowTreeClient() |
| 121 : binding_(this), | 121 : binding_(this), |
| 122 client_id_(0), | 122 client_id_(0), |
| 123 root_window_id_(0), | 123 root_window_id_(0), |
| 124 // Start with a random large number so tests can use lower ids if they | 124 // Start with a random large number so tests can use lower ids if they |
| 125 // want. | 125 // want. |
| 126 next_change_id_(10000), | 126 next_change_id_(10000), |
| 127 waiting_change_id_(0), | 127 waiting_change_id_(0), |
| 128 on_change_completed_result_(false), | 128 on_change_completed_result_(false), |
| 129 track_root_bounds_changes_(false) { | 129 track_root_bounds_changes_(false) { |
| 130 tracker_.set_delegate(this); | 130 tracker_.set_delegate(this); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 uint32_t next_change_id_; | 429 uint32_t next_change_id_; |
| 430 uint32_t waiting_change_id_; | 430 uint32_t waiting_change_id_; |
| 431 bool on_change_completed_result_; | 431 bool on_change_completed_result_; |
| 432 bool track_root_bounds_changes_; | 432 bool track_root_bounds_changes_; |
| 433 std::unique_ptr<base::RunLoop> change_completed_run_loop_; | 433 std::unique_ptr<base::RunLoop> change_completed_run_loop_; |
| 434 | 434 |
| 435 std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManager>> | 435 std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManager>> |
| 436 window_manager_binding_; | 436 window_manager_binding_; |
| 437 mojom::WindowManagerClientAssociatedPtr window_manager_client_; | 437 mojom::WindowManagerClientAssociatedPtr window_manager_client_; |
| 438 | 438 |
| 439 DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClientImpl); | 439 DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient); |
| 440 }; | 440 }; |
| 441 | 441 |
| 442 // ----------------------------------------------------------------------------- | 442 // ----------------------------------------------------------------------------- |
| 443 | 443 |
| 444 // InterfaceFactory for vending TestWindowTreeClientImpls. | 444 // InterfaceFactory for vending TestWindowTreeClients. |
| 445 class WindowTreeClientFactory | 445 class WindowTreeClientFactory |
| 446 : public shell::InterfaceFactory<WindowTreeClient> { | 446 : public shell::InterfaceFactory<WindowTreeClient> { |
| 447 public: | 447 public: |
| 448 WindowTreeClientFactory() {} | 448 WindowTreeClientFactory() {} |
| 449 ~WindowTreeClientFactory() override {} | 449 ~WindowTreeClientFactory() override {} |
| 450 | 450 |
| 451 // Runs a nested MessageLoop until a new instance has been created. | 451 // Runs a nested MessageLoop until a new instance has been created. |
| 452 std::unique_ptr<TestWindowTreeClientImpl> WaitForInstance() { | 452 std::unique_ptr<TestWindowTreeClient> WaitForInstance() { |
| 453 if (!client_impl_.get()) { | 453 if (!client_impl_.get()) { |
| 454 DCHECK(!run_loop_); | 454 DCHECK(!run_loop_); |
| 455 run_loop_.reset(new base::RunLoop); | 455 run_loop_.reset(new base::RunLoop); |
| 456 run_loop_->Run(); | 456 run_loop_->Run(); |
| 457 run_loop_.reset(); | 457 run_loop_.reset(); |
| 458 } | 458 } |
| 459 return std::move(client_impl_); | 459 return std::move(client_impl_); |
| 460 } | 460 } |
| 461 | 461 |
| 462 private: | 462 private: |
| 463 // InterfaceFactory<WindowTreeClient>: | 463 // InterfaceFactory<WindowTreeClient>: |
| 464 void Create(Connection* connection, | 464 void Create(Connection* connection, |
| 465 InterfaceRequest<WindowTreeClient> request) override { | 465 InterfaceRequest<WindowTreeClient> request) override { |
| 466 client_impl_.reset(new TestWindowTreeClientImpl()); | 466 client_impl_.reset(new TestWindowTreeClient()); |
| 467 client_impl_->Bind(std::move(request)); | 467 client_impl_->Bind(std::move(request)); |
| 468 if (run_loop_.get()) | 468 if (run_loop_.get()) |
| 469 run_loop_->Quit(); | 469 run_loop_->Quit(); |
| 470 } | 470 } |
| 471 | 471 |
| 472 std::unique_ptr<TestWindowTreeClientImpl> client_impl_; | 472 std::unique_ptr<TestWindowTreeClient> client_impl_; |
| 473 std::unique_ptr<base::RunLoop> run_loop_; | 473 std::unique_ptr<base::RunLoop> run_loop_; |
| 474 | 474 |
| 475 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientFactory); | 475 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientFactory); |
| 476 }; | 476 }; |
| 477 | 477 |
| 478 } // namespace | 478 } // namespace |
| 479 | 479 |
| 480 class WindowTreeClientTest : public WindowServerShellTestBase { | 480 class WindowTreeClientTest : public WindowServerShellTestBase { |
| 481 public: | 481 public: |
| 482 WindowTreeClientTest() | 482 WindowTreeClientTest() |
| 483 : client_id_1_(0), client_id_2_(0), root_window_id_(0) {} | 483 : client_id_1_(0), client_id_2_(0), root_window_id_(0) {} |
| 484 | 484 |
| 485 ~WindowTreeClientTest() override {} | 485 ~WindowTreeClientTest() override {} |
| 486 | 486 |
| 487 protected: | 487 protected: |
| 488 // Returns the changes from the various clients. | 488 // Returns the changes from the various clients. |
| 489 std::vector<Change>* changes1() { return wt_client1_->tracker()->changes(); } | 489 std::vector<Change>* changes1() { return wt_client1_->tracker()->changes(); } |
| 490 std::vector<Change>* changes2() { return wt_client2_->tracker()->changes(); } | 490 std::vector<Change>* changes2() { return wt_client2_->tracker()->changes(); } |
| 491 std::vector<Change>* changes3() { return wt_client3_->tracker()->changes(); } | 491 std::vector<Change>* changes3() { return wt_client3_->tracker()->changes(); } |
| 492 | 492 |
| 493 // Various clients. |wt1()|, being the first client, has special permissions | 493 // Various clients. |wt1()|, being the first client, has special permissions |
| 494 // (it's treated as the window manager). | 494 // (it's treated as the window manager). |
| 495 WindowTree* wt1() { return wt_client1_->tree(); } | 495 WindowTree* wt1() { return wt_client1_->tree(); } |
| 496 WindowTree* wt2() { return wt_client2_->tree(); } | 496 WindowTree* wt2() { return wt_client2_->tree(); } |
| 497 WindowTree* wt3() { return wt_client3_->tree(); } | 497 WindowTree* wt3() { return wt_client3_->tree(); } |
| 498 | 498 |
| 499 TestWindowTreeClientImpl* wt_client1() { return wt_client1_.get(); } | 499 TestWindowTreeClient* wt_client1() { return wt_client1_.get(); } |
| 500 TestWindowTreeClientImpl* wt_client2() { return wt_client2_.get(); } | 500 TestWindowTreeClient* wt_client2() { return wt_client2_.get(); } |
| 501 TestWindowTreeClientImpl* wt_client3() { return wt_client3_.get(); } | 501 TestWindowTreeClient* wt_client3() { return wt_client3_.get(); } |
| 502 | 502 |
| 503 Id root_window_id() const { return root_window_id_; } | 503 Id root_window_id() const { return root_window_id_; } |
| 504 | 504 |
| 505 int client_id_1() const { return client_id_1_; } | 505 int client_id_1() const { return client_id_1_; } |
| 506 int client_id_2() const { return client_id_2_; } | 506 int client_id_2() const { return client_id_2_; } |
| 507 | 507 |
| 508 void EstablishSecondClientWithRoot(Id root_id) { | 508 void EstablishSecondClientWithRoot(Id root_id) { |
| 509 ASSERT_TRUE(wt_client2_.get() == nullptr); | 509 ASSERT_TRUE(wt_client2_.get() == nullptr); |
| 510 wt_client2_ = | 510 wt_client2_ = |
| 511 EstablishClientViaEmbed(wt1(), root_id, &client_id_2_); | 511 EstablishClientViaEmbed(wt1(), root_id, &client_id_2_); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 527 ChangeWindowDescription(*changes2())); | 527 ChangeWindowDescription(*changes2())); |
| 528 } | 528 } |
| 529 } | 529 } |
| 530 | 530 |
| 531 void EstablishThirdClient(WindowTree* owner, Id root_id) { | 531 void EstablishThirdClient(WindowTree* owner, Id root_id) { |
| 532 ASSERT_TRUE(wt_client3_.get() == nullptr); | 532 ASSERT_TRUE(wt_client3_.get() == nullptr); |
| 533 wt_client3_ = EstablishClientViaEmbed(owner, root_id, nullptr); | 533 wt_client3_ = EstablishClientViaEmbed(owner, root_id, nullptr); |
| 534 ASSERT_TRUE(wt_client3_.get() != nullptr); | 534 ASSERT_TRUE(wt_client3_.get() != nullptr); |
| 535 } | 535 } |
| 536 | 536 |
| 537 std::unique_ptr<TestWindowTreeClientImpl> WaitForWindowTreeClient() { | 537 std::unique_ptr<TestWindowTreeClient> WaitForWindowTreeClient() { |
| 538 return client_factory_->WaitForInstance(); | 538 return client_factory_->WaitForInstance(); |
| 539 } | 539 } |
| 540 | 540 |
| 541 // Establishes a new client by way of Embed() on the specified WindowTree. | 541 // Establishes a new client by way of Embed() on the specified WindowTree. |
| 542 std::unique_ptr<TestWindowTreeClientImpl> EstablishClientViaEmbed( | 542 std::unique_ptr<TestWindowTreeClient> EstablishClientViaEmbed( |
| 543 WindowTree* owner, | 543 WindowTree* owner, |
| 544 Id root_id, | 544 Id root_id, |
| 545 int* client_id) { | 545 int* client_id) { |
| 546 return EstablishClientViaEmbedWithPolicyBitmask(owner, root_id, client_id); | 546 return EstablishClientViaEmbedWithPolicyBitmask(owner, root_id, client_id); |
| 547 } | 547 } |
| 548 | 548 |
| 549 std::unique_ptr<TestWindowTreeClientImpl> | 549 std::unique_ptr<TestWindowTreeClient> |
| 550 EstablishClientViaEmbedWithPolicyBitmask(WindowTree* owner, | 550 EstablishClientViaEmbedWithPolicyBitmask(WindowTree* owner, |
| 551 Id root_id, | 551 Id root_id, |
| 552 int* client_id) { | 552 int* client_id) { |
| 553 if (!EmbedUrl(connector(), owner, test_name(), root_id)) { | 553 if (!EmbedUrl(connector(), owner, test_name(), root_id)) { |
| 554 ADD_FAILURE() << "Embed() failed"; | 554 ADD_FAILURE() << "Embed() failed"; |
| 555 return nullptr; | 555 return nullptr; |
| 556 } | 556 } |
| 557 std::unique_ptr<TestWindowTreeClientImpl> client = | 557 std::unique_ptr<TestWindowTreeClient> client = |
| 558 client_factory_->WaitForInstance(); | 558 client_factory_->WaitForInstance(); |
| 559 if (!client.get()) { | 559 if (!client.get()) { |
| 560 ADD_FAILURE() << "WaitForInstance failed"; | 560 ADD_FAILURE() << "WaitForInstance failed"; |
| 561 return nullptr; | 561 return nullptr; |
| 562 } | 562 } |
| 563 client->WaitForOnEmbed(); | 563 client->WaitForOnEmbed(); |
| 564 | 564 |
| 565 EXPECT_EQ("OnEmbed", | 565 EXPECT_EQ("OnEmbed", |
| 566 SingleChangeToDescription(*client->tracker()->changes())); | 566 SingleChangeToDescription(*client->tracker()->changes())); |
| 567 if (client_id) | 567 if (client_id) |
| 568 *client_id = (*client->tracker()->changes())[0].client_id; | 568 *client_id = (*client->tracker()->changes())[0].client_id; |
| 569 return client; | 569 return client; |
| 570 } | 570 } |
| 571 | 571 |
| 572 // WindowServerShellTestBase: | 572 // WindowServerShellTestBase: |
| 573 bool AcceptConnection(shell::Connection* connection) override { | 573 bool AcceptConnection(shell::Connection* connection) override { |
| 574 connection->AddInterface(client_factory_.get()); | 574 connection->AddInterface(client_factory_.get()); |
| 575 return true; | 575 return true; |
| 576 } | 576 } |
| 577 | 577 |
| 578 void SetUp() override { | 578 void SetUp() override { |
| 579 client_factory_.reset(new WindowTreeClientFactory()); | 579 client_factory_.reset(new WindowTreeClientFactory()); |
| 580 | 580 |
| 581 WindowServerShellTestBase::SetUp(); | 581 WindowServerShellTestBase::SetUp(); |
| 582 | 582 |
| 583 mojom::WindowTreeHostFactoryPtr factory; | 583 mojom::WindowTreeHostFactoryPtr factory; |
| 584 connector()->ConnectToInterface("mojo:mus", &factory); | 584 connector()->ConnectToInterface("mojo:mus", &factory); |
| 585 | 585 |
| 586 mojom::WindowTreeClientPtr tree_client_ptr; | 586 mojom::WindowTreeClientPtr tree_client_ptr; |
| 587 wt_client1_.reset(new TestWindowTreeClientImpl()); | 587 wt_client1_.reset(new TestWindowTreeClient()); |
| 588 wt_client1_->Bind(GetProxy(&tree_client_ptr)); | 588 wt_client1_->Bind(GetProxy(&tree_client_ptr)); |
| 589 | 589 |
| 590 factory->CreateWindowTreeHost(GetProxy(&host_), | 590 factory->CreateWindowTreeHost(GetProxy(&host_), |
| 591 std::move(tree_client_ptr)); | 591 std::move(tree_client_ptr)); |
| 592 | 592 |
| 593 // Next we should get an embed call on the "window manager" client. | 593 // Next we should get an embed call on the "window manager" client. |
| 594 wt_client1_->WaitForOnEmbed(); | 594 wt_client1_->WaitForOnEmbed(); |
| 595 | 595 |
| 596 ASSERT_EQ(1u, changes1()->size()); | 596 ASSERT_EQ(1u, changes1()->size()); |
| 597 EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type); | 597 EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 609 void TearDown() override { | 609 void TearDown() override { |
| 610 // Destroy these before the message loop is destroyed (happens in | 610 // Destroy these before the message loop is destroyed (happens in |
| 611 // WindowServerShellTestBase::TearDown). | 611 // WindowServerShellTestBase::TearDown). |
| 612 wt_client1_.reset(); | 612 wt_client1_.reset(); |
| 613 wt_client2_.reset(); | 613 wt_client2_.reset(); |
| 614 wt_client3_.reset(); | 614 wt_client3_.reset(); |
| 615 client_factory_.reset(); | 615 client_factory_.reset(); |
| 616 WindowServerShellTestBase::TearDown(); | 616 WindowServerShellTestBase::TearDown(); |
| 617 } | 617 } |
| 618 | 618 |
| 619 std::unique_ptr<TestWindowTreeClientImpl> wt_client1_; | 619 std::unique_ptr<TestWindowTreeClient> wt_client1_; |
| 620 std::unique_ptr<TestWindowTreeClientImpl> wt_client2_; | 620 std::unique_ptr<TestWindowTreeClient> wt_client2_; |
| 621 std::unique_ptr<TestWindowTreeClientImpl> wt_client3_; | 621 std::unique_ptr<TestWindowTreeClient> wt_client3_; |
| 622 | 622 |
| 623 mojom::WindowTreeHostPtr host_; | 623 mojom::WindowTreeHostPtr host_; |
| 624 | 624 |
| 625 private: | 625 private: |
| 626 std::unique_ptr<WindowTreeClientFactory> client_factory_; | 626 std::unique_ptr<WindowTreeClientFactory> client_factory_; |
| 627 int client_id_1_; | 627 int client_id_1_; |
| 628 int client_id_2_; | 628 int client_id_2_; |
| 629 Id root_window_id_; | 629 Id root_window_id_; |
| 630 | 630 |
| 631 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTest); | 631 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTest); |
| (...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1358 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_3_1) + | 1358 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_3_1) + |
| 1359 " old_parent=null new_parent=" + IdToString(window_1_1), | 1359 " old_parent=null new_parent=" + IdToString(window_1_1), |
| 1360 SingleChangeToDescription(*changes1())); | 1360 SingleChangeToDescription(*changes1())); |
| 1361 } | 1361 } |
| 1362 | 1362 |
| 1363 // Embed 1,1 again. | 1363 // Embed 1,1 again. |
| 1364 { | 1364 { |
| 1365 changes3()->clear(); | 1365 changes3()->clear(); |
| 1366 | 1366 |
| 1367 // We should get a new client for the new embedding. | 1367 // We should get a new client for the new embedding. |
| 1368 std::unique_ptr<TestWindowTreeClientImpl> client4( | 1368 std::unique_ptr<TestWindowTreeClient> client4( |
| 1369 EstablishClientViaEmbed(wt1(), window_1_1, nullptr)); | 1369 EstablishClientViaEmbed(wt1(), window_1_1, nullptr)); |
| 1370 ASSERT_TRUE(client4.get()); | 1370 ASSERT_TRUE(client4.get()); |
| 1371 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]", | 1371 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]", |
| 1372 ChangeWindowDescription(*client4->tracker()->changes())); | 1372 ChangeWindowDescription(*client4->tracker()->changes())); |
| 1373 | 1373 |
| 1374 // And 3 should get an unembed and delete. | 1374 // And 3 should get an unembed and delete. |
| 1375 wt_client3_->WaitForChangeCount(2); | 1375 wt_client3_->WaitForChangeCount(2); |
| 1376 EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1), | 1376 EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1), |
| 1377 ChangesToDescription1(*changes3())[0]); | 1377 ChangesToDescription1(*changes3())[0]); |
| 1378 EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1), | 1378 EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1), |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1796 SingleChangeToDescription(*changes1())); | 1796 SingleChangeToDescription(*changes1())); |
| 1797 std::vector<TestWindow> windows; | 1797 std::vector<TestWindow> windows; |
| 1798 GetWindowTree(wt1(), window_1_1, &windows); | 1798 GetWindowTree(wt1(), window_1_1, &windows); |
| 1799 EXPECT_FALSE(windows.empty()); | 1799 EXPECT_FALSE(windows.empty()); |
| 1800 } | 1800 } |
| 1801 | 1801 |
| 1802 // Verifies Embed() works when supplying a WindowTreeClient. | 1802 // Verifies Embed() works when supplying a WindowTreeClient. |
| 1803 TEST_F(WindowTreeClientTest, EmbedSupplyingWindowTreeClient) { | 1803 TEST_F(WindowTreeClientTest, EmbedSupplyingWindowTreeClient) { |
| 1804 ASSERT_TRUE(wt_client1()->NewWindow(1)); | 1804 ASSERT_TRUE(wt_client1()->NewWindow(1)); |
| 1805 | 1805 |
| 1806 TestWindowTreeClientImpl client2; | 1806 TestWindowTreeClient client2; |
| 1807 mojom::WindowTreeClientPtr client2_ptr; | 1807 mojom::WindowTreeClientPtr client2_ptr; |
| 1808 mojo::Binding<WindowTreeClient> client2_binding(&client2, &client2_ptr); | 1808 mojo::Binding<WindowTreeClient> client2_binding(&client2, &client2_ptr); |
| 1809 ASSERT_TRUE(Embed(wt1(), BuildWindowId(client_id_1(), 1), | 1809 ASSERT_TRUE(Embed(wt1(), BuildWindowId(client_id_1(), 1), |
| 1810 std::move(client2_ptr))); | 1810 std::move(client2_ptr))); |
| 1811 client2.WaitForOnEmbed(); | 1811 client2.WaitForOnEmbed(); |
| 1812 EXPECT_EQ("OnEmbed", | 1812 EXPECT_EQ("OnEmbed", |
| 1813 SingleChangeToDescription(*client2.tracker()->changes())); | 1813 SingleChangeToDescription(*client2.tracker()->changes())); |
| 1814 } | 1814 } |
| 1815 | 1815 |
| 1816 TEST_F(WindowTreeClientTest, EmbedFailsFromOtherClient) { | 1816 TEST_F(WindowTreeClientTest, EmbedFailsFromOtherClient) { |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2027 | 2027 |
| 2028 // TODO(sky): make sure coverage of what was | 2028 // TODO(sky): make sure coverage of what was |
| 2029 // WindowManagerTest.SecondEmbedRoot_InitService and | 2029 // WindowManagerTest.SecondEmbedRoot_InitService and |
| 2030 // WindowManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window | 2030 // WindowManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window |
| 2031 // manager | 2031 // manager |
| 2032 // tests. | 2032 // tests. |
| 2033 | 2033 |
| 2034 } // namespace test | 2034 } // namespace test |
| 2035 } // namespace ws | 2035 } // namespace ws |
| 2036 } // namespace mus | 2036 } // namespace mus |
| OLD | NEW |