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