1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/midi/midi_manager.h"
10 #include "base/logging.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/system_monitor/system_monitor.h"
16 #include "testing/gtest/include/gtest/gtest.h"
23 class FakeMidiManager
: public MidiManager
{
25 FakeMidiManager() : start_initialization_is_called_(false) {}
26 ~FakeMidiManager() override
{}
28 // MidiManager implementation.
29 void StartInitialization() override
{
30 start_initialization_is_called_
= true;
33 void DispatchSendMidiData(MidiManagerClient
* client
,
35 const std::vector
<uint8
>& data
,
36 double timestamp
) override
{}
38 // Utility functions for testing.
39 void CallCompleteInitialization(MidiResult result
) {
40 CompleteInitialization(result
);
43 size_t GetClientCount() const {
44 return clients_size_for_testing();
47 size_t GetPendingClientCount() const {
48 return pending_clients_size_for_testing();
51 bool start_initialization_is_called_
;
54 DISALLOW_COPY_AND_ASSIGN(FakeMidiManager
);
57 class FakeMidiManagerClient
: public MidiManagerClient
{
59 FakeMidiManagerClient()
60 : result_(MIDI_NOT_SUPPORTED
),
61 wait_for_result_(true) {}
62 ~FakeMidiManagerClient() override
{}
64 // MidiManagerClient implementation.
65 void AddInputPort(const MidiPortInfo
& info
) override
{}
66 void AddOutputPort(const MidiPortInfo
& info
) override
{}
67 void SetInputPortState(uint32 port_index
, MidiPortState state
) override
{}
68 void SetOutputPortState(uint32 port_index
, MidiPortState state
) override
{}
70 void CompleteStartSession(MidiResult result
) override
{
71 EXPECT_TRUE(wait_for_result_
);
73 wait_for_result_
= false;
76 void ReceiveMidiData(uint32 port_index
,
79 double timestamp
) override
{}
80 void AccumulateMidiBytesSent(size_t size
) override
{}
82 MidiResult
result() const { return result_
; }
84 MidiResult
WaitForResult() {
85 while (wait_for_result_
) {
86 base::RunLoop run_loop
;
87 run_loop
.RunUntilIdle();
94 bool wait_for_result_
;
96 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient
);
99 class MidiManagerTest
: public ::testing::Test
{
102 : manager_(new FakeMidiManager
),
103 message_loop_(new base::MessageLoop
) {}
104 ~MidiManagerTest() override
{}
107 void StartTheFirstSession(FakeMidiManagerClient
* client
) {
108 EXPECT_FALSE(manager_
->start_initialization_is_called_
);
109 EXPECT_EQ(0U, manager_
->GetClientCount());
110 EXPECT_EQ(0U, manager_
->GetPendingClientCount());
111 manager_
->StartSession(client
);
112 EXPECT_EQ(0U, manager_
->GetClientCount());
113 EXPECT_EQ(1U, manager_
->GetPendingClientCount());
114 EXPECT_TRUE(manager_
->start_initialization_is_called_
);
115 EXPECT_EQ(0U, manager_
->GetClientCount());
116 EXPECT_EQ(1U, manager_
->GetPendingClientCount());
117 EXPECT_TRUE(manager_
->start_initialization_is_called_
);
120 void StartTheNthSession(FakeMidiManagerClient
* client
, size_t nth
) {
121 EXPECT_EQ(nth
!= 1, manager_
->start_initialization_is_called_
);
122 EXPECT_EQ(0U, manager_
->GetClientCount());
123 EXPECT_EQ(nth
- 1, manager_
->GetPendingClientCount());
125 // StartInitialization() should not be called for the second and later
127 manager_
->start_initialization_is_called_
= false;
128 manager_
->StartSession(client
);
129 EXPECT_EQ(nth
== 1, manager_
->start_initialization_is_called_
);
130 manager_
->start_initialization_is_called_
= true;
133 void EndSession(FakeMidiManagerClient
* client
, size_t before
, size_t after
) {
134 EXPECT_EQ(before
, manager_
->GetClientCount());
135 manager_
->EndSession(client
);
136 EXPECT_EQ(after
, manager_
->GetClientCount());
139 void CompleteInitialization(MidiResult result
) {
140 manager_
->CallCompleteInitialization(result
);
143 void RunLoopUntilIdle() {
144 base::RunLoop run_loop
;
145 run_loop
.RunUntilIdle();
149 scoped_ptr
<FakeMidiManager
> manager_
;
152 scoped_ptr
<base::MessageLoop
> message_loop_
;
154 DISALLOW_COPY_AND_ASSIGN(MidiManagerTest
);
157 TEST_F(MidiManagerTest
, StartAndEndSession
) {
158 scoped_ptr
<FakeMidiManagerClient
> client
;
159 client
.reset(new FakeMidiManagerClient
);
161 StartTheFirstSession(client
.get());
162 CompleteInitialization(MIDI_OK
);
163 EXPECT_EQ(MIDI_OK
, client
->WaitForResult());
164 EndSession(client
.get(), 1U, 0U);
167 TEST_F(MidiManagerTest
, StartAndEndSessionWithError
) {
168 scoped_ptr
<FakeMidiManagerClient
> client
;
169 client
.reset(new FakeMidiManagerClient
);
171 StartTheFirstSession(client
.get());
172 CompleteInitialization(MIDI_INITIALIZATION_ERROR
);
173 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, client
->WaitForResult());
174 EndSession(client
.get(), 0U, 0U);
177 TEST_F(MidiManagerTest
, StartMultipleSessions
) {
178 scoped_ptr
<FakeMidiManagerClient
> client1
;
179 scoped_ptr
<FakeMidiManagerClient
> client2
;
180 scoped_ptr
<FakeMidiManagerClient
> client3
;
181 client1
.reset(new FakeMidiManagerClient
);
182 client2
.reset(new FakeMidiManagerClient
);
183 client3
.reset(new FakeMidiManagerClient
);
185 StartTheFirstSession(client1
.get());
186 StartTheNthSession(client2
.get(), 2);
187 StartTheNthSession(client3
.get(), 3);
188 CompleteInitialization(MIDI_OK
);
189 EXPECT_EQ(MIDI_OK
, client1
->WaitForResult());
190 EXPECT_EQ(MIDI_OK
, client2
->WaitForResult());
191 EXPECT_EQ(MIDI_OK
, client3
->WaitForResult());
192 EndSession(client1
.get(), 3U, 2U);
193 EndSession(client2
.get(), 2U, 1U);
194 EndSession(client3
.get(), 1U, 0U);
197 // TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
198 // sessions with multiple client_id.
200 TEST_F(MidiManagerTest
, TooManyPendingSessions
) {
201 // Push as many client requests for starting session as possible.
202 ScopedVector
<FakeMidiManagerClient
> many_existing_clients
;
203 many_existing_clients
.resize(MidiManager::kMaxPendingClientCount
);
204 for (size_t i
= 0; i
< MidiManager::kMaxPendingClientCount
; ++i
) {
205 many_existing_clients
[i
] = new FakeMidiManagerClient
;
206 StartTheNthSession(many_existing_clients
[i
], i
+ 1);
209 // Push the last client that should be rejected for too many pending requests.
210 scoped_ptr
<FakeMidiManagerClient
> additional_client(
211 new FakeMidiManagerClient
);
212 manager_
->start_initialization_is_called_
= false;
213 manager_
->StartSession(additional_client
.get());
214 EXPECT_FALSE(manager_
->start_initialization_is_called_
);
215 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, additional_client
->result());
217 // Other clients still should not receive a result.
219 for (size_t i
= 0; i
< many_existing_clients
.size(); ++i
)
220 EXPECT_EQ(MIDI_NOT_SUPPORTED
, many_existing_clients
[i
]->result());
222 // The result MIDI_OK should be distributed to other clients.
223 CompleteInitialization(MIDI_OK
);
224 for (size_t i
= 0; i
< many_existing_clients
.size(); ++i
)
225 EXPECT_EQ(MIDI_OK
, many_existing_clients
[i
]->WaitForResult());
227 // Close all successful sessions in FIFO order.
228 size_t sessions
= many_existing_clients
.size();
229 for (size_t i
= 0; i
< many_existing_clients
.size(); ++i
, --sessions
)
230 EndSession(many_existing_clients
[i
], sessions
, sessions
- 1);
233 TEST_F(MidiManagerTest
, AbortSession
) {
234 // A client starting a session can be destructed while an asynchronous
235 // initialization is performed.
236 scoped_ptr
<FakeMidiManagerClient
> client
;
237 client
.reset(new FakeMidiManagerClient
);
239 StartTheFirstSession(client
.get());
240 EndSession(client
.get(), 0, 0);
243 // Following function should not call the destructed |client| function.
244 CompleteInitialization(MIDI_OK
);
245 base::RunLoop run_loop
;
246 run_loop
.RunUntilIdle();
249 TEST_F(MidiManagerTest
, CreateMidiManager
) {
250 // SystemMonitor is needed on Windows.
251 base::SystemMonitor system_monitor
;
253 scoped_ptr
<FakeMidiManagerClient
> client
;
254 client
.reset(new FakeMidiManagerClient
);
256 scoped_ptr
<MidiManager
> manager(MidiManager::Create());
257 manager
->StartSession(client
.get());
259 MidiResult result
= client
->WaitForResult();
260 // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
261 // Do not change the condition for disabling this test.
262 #if !defined(OS_MACOSX) && !defined(OS_WIN) && \
263 !(defined(USE_ALSA) && defined(USE_UDEV)) && !defined(OS_ANDROID)
264 EXPECT_EQ(MIDI_NOT_SUPPORTED
, result
);
265 #elif defined(USE_ALSA)
266 // Temporary until http://crbug.com/371230 is resolved.
267 EXPECT_TRUE((result
== MIDI_OK
) || (result
== MIDI_INITIALIZATION_ERROR
));
269 EXPECT_EQ(MIDI_OK
, result
);