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 "testing/gtest/include/gtest/gtest.h"
21 class FakeMidiManager
: public MidiManager
{
23 FakeMidiManager() : start_initialization_is_called_(false) {}
24 ~FakeMidiManager() override
{}
26 // MidiManager implementation.
27 void StartInitialization() override
{
28 start_initialization_is_called_
= true;
31 void DispatchSendMidiData(MidiManagerClient
* client
,
33 const std::vector
<uint8
>& data
,
34 double timestamp
) override
{}
36 // Utility functions for testing.
37 void CallCompleteInitialization(MidiResult result
) {
38 CompleteInitialization(result
);
41 size_t GetClientCount() const {
42 return clients_size_for_testing();
45 size_t GetPendingClientCount() const {
46 return pending_clients_size_for_testing();
49 bool start_initialization_is_called_
;
52 DISALLOW_COPY_AND_ASSIGN(FakeMidiManager
);
55 class FakeMidiManagerClient
: public MidiManagerClient
{
57 FakeMidiManagerClient()
58 : result_(MIDI_NOT_SUPPORTED
),
59 wait_for_result_(true) {}
60 ~FakeMidiManagerClient() override
{}
62 // MidiManagerClient implementation.
63 void AddInputPort(const MidiPortInfo
& info
) override
{}
64 void AddOutputPort(const MidiPortInfo
& info
) override
{}
66 void CompleteStartSession(MidiResult result
) override
{
67 EXPECT_TRUE(wait_for_result_
);
69 wait_for_result_
= false;
72 void ReceiveMidiData(uint32 port_index
,
75 double timestamp
) override
{}
76 void AccumulateMidiBytesSent(size_t size
) override
{}
78 MidiResult
result() const { return result_
; }
80 MidiResult
WaitForResult() {
81 while (wait_for_result_
) {
82 base::RunLoop run_loop
;
83 run_loop
.RunUntilIdle();
90 bool wait_for_result_
;
92 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient
);
95 class MidiManagerTest
: public ::testing::Test
{
98 : manager_(new FakeMidiManager
),
99 message_loop_(new base::MessageLoop
) {}
100 ~MidiManagerTest() override
{}
103 void StartTheFirstSession(FakeMidiManagerClient
* client
) {
104 EXPECT_FALSE(manager_
->start_initialization_is_called_
);
105 EXPECT_EQ(0U, manager_
->GetClientCount());
106 EXPECT_EQ(0U, manager_
->GetPendingClientCount());
107 manager_
->StartSession(client
);
108 EXPECT_EQ(0U, manager_
->GetClientCount());
109 EXPECT_EQ(1U, manager_
->GetPendingClientCount());
110 EXPECT_TRUE(manager_
->start_initialization_is_called_
);
111 EXPECT_EQ(0U, manager_
->GetClientCount());
112 EXPECT_EQ(1U, manager_
->GetPendingClientCount());
113 EXPECT_TRUE(manager_
->start_initialization_is_called_
);
116 void StartTheNthSession(FakeMidiManagerClient
* client
, size_t nth
) {
117 EXPECT_EQ(nth
!= 1, manager_
->start_initialization_is_called_
);
118 EXPECT_EQ(0U, manager_
->GetClientCount());
119 EXPECT_EQ(nth
- 1, manager_
->GetPendingClientCount());
121 // StartInitialization() should not be called for the second and later
123 manager_
->start_initialization_is_called_
= false;
124 manager_
->StartSession(client
);
125 EXPECT_EQ(nth
== 1, manager_
->start_initialization_is_called_
);
126 manager_
->start_initialization_is_called_
= true;
129 void EndSession(FakeMidiManagerClient
* client
, size_t before
, size_t after
) {
130 EXPECT_EQ(before
, manager_
->GetClientCount());
131 manager_
->EndSession(client
);
132 EXPECT_EQ(after
, manager_
->GetClientCount());
135 void CompleteInitialization(MidiResult result
) {
136 manager_
->CallCompleteInitialization(result
);
139 void RunLoopUntilIdle() {
140 base::RunLoop run_loop
;
141 run_loop
.RunUntilIdle();
145 scoped_ptr
<FakeMidiManager
> manager_
;
148 scoped_ptr
<base::MessageLoop
> message_loop_
;
150 DISALLOW_COPY_AND_ASSIGN(MidiManagerTest
);
153 TEST_F(MidiManagerTest
, StartAndEndSession
) {
154 scoped_ptr
<FakeMidiManagerClient
> client
;
155 client
.reset(new FakeMidiManagerClient
);
157 StartTheFirstSession(client
.get());
158 CompleteInitialization(MIDI_OK
);
159 EXPECT_EQ(MIDI_OK
, client
->WaitForResult());
160 EndSession(client
.get(), 1U, 0U);
163 TEST_F(MidiManagerTest
, StartAndEndSessionWithError
) {
164 scoped_ptr
<FakeMidiManagerClient
> client
;
165 client
.reset(new FakeMidiManagerClient
);
167 StartTheFirstSession(client
.get());
168 CompleteInitialization(MIDI_INITIALIZATION_ERROR
);
169 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, client
->WaitForResult());
170 EndSession(client
.get(), 0U, 0U);
173 TEST_F(MidiManagerTest
, StartMultipleSessions
) {
174 scoped_ptr
<FakeMidiManagerClient
> client1
;
175 scoped_ptr
<FakeMidiManagerClient
> client2
;
176 scoped_ptr
<FakeMidiManagerClient
> client3
;
177 client1
.reset(new FakeMidiManagerClient
);
178 client2
.reset(new FakeMidiManagerClient
);
179 client3
.reset(new FakeMidiManagerClient
);
181 StartTheFirstSession(client1
.get());
182 StartTheNthSession(client2
.get(), 2);
183 StartTheNthSession(client3
.get(), 3);
184 CompleteInitialization(MIDI_OK
);
185 EXPECT_EQ(MIDI_OK
, client1
->WaitForResult());
186 EXPECT_EQ(MIDI_OK
, client2
->WaitForResult());
187 EXPECT_EQ(MIDI_OK
, client3
->WaitForResult());
188 EndSession(client1
.get(), 3U, 2U);
189 EndSession(client2
.get(), 2U, 1U);
190 EndSession(client3
.get(), 1U, 0U);
193 // TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
194 // sessions with multiple client_id.
196 TEST_F(MidiManagerTest
, TooManyPendingSessions
) {
197 // Push as many client requests for starting session as possible.
198 ScopedVector
<FakeMidiManagerClient
> many_existing_clients
;
199 many_existing_clients
.resize(MidiManager::kMaxPendingClientCount
);
200 for (size_t i
= 0; i
< MidiManager::kMaxPendingClientCount
; ++i
) {
201 many_existing_clients
[i
] = new FakeMidiManagerClient
;
202 StartTheNthSession(many_existing_clients
[i
], i
+ 1);
205 // Push the last client that should be rejected for too many pending requests.
206 scoped_ptr
<FakeMidiManagerClient
> additional_client(
207 new FakeMidiManagerClient
);
208 manager_
->start_initialization_is_called_
= false;
209 manager_
->StartSession(additional_client
.get());
210 EXPECT_FALSE(manager_
->start_initialization_is_called_
);
211 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, additional_client
->result());
213 // Other clients still should not receive a result.
215 for (size_t i
= 0; i
< many_existing_clients
.size(); ++i
)
216 EXPECT_EQ(MIDI_NOT_SUPPORTED
, many_existing_clients
[i
]->result());
218 // The result MIDI_OK should be distributed to other clients.
219 CompleteInitialization(MIDI_OK
);
220 for (size_t i
= 0; i
< many_existing_clients
.size(); ++i
)
221 EXPECT_EQ(MIDI_OK
, many_existing_clients
[i
]->WaitForResult());
223 // Close all successful sessions in FIFO order.
224 size_t sessions
= many_existing_clients
.size();
225 for (size_t i
= 0; i
< many_existing_clients
.size(); ++i
, --sessions
)
226 EndSession(many_existing_clients
[i
], sessions
, sessions
- 1);
229 TEST_F(MidiManagerTest
, AbortSession
) {
230 // A client starting a session can be destructed while an asynchronous
231 // initialization is performed.
232 scoped_ptr
<FakeMidiManagerClient
> client
;
233 client
.reset(new FakeMidiManagerClient
);
235 StartTheFirstSession(client
.get());
236 EndSession(client
.get(), 0, 0);
239 // Following function should not call the destructed |client| function.
240 CompleteInitialization(MIDI_OK
);
241 base::RunLoop run_loop
;
242 run_loop
.RunUntilIdle();
245 TEST_F(MidiManagerTest
, CreateMidiManager
) {
246 scoped_ptr
<FakeMidiManagerClient
> client
;
247 client
.reset(new FakeMidiManagerClient
);
249 scoped_ptr
<MidiManager
> manager(MidiManager::Create());
250 manager
->StartSession(client
.get());
252 MidiResult result
= client
->WaitForResult();
253 // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
254 // Do not change the condition for disabling this test.
255 #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
256 !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
257 EXPECT_EQ(MIDI_NOT_SUPPORTED
, result
);
258 #elif defined(USE_ALSA)
259 // Temporary until http://crbug.com/371230 is resolved.
260 EXPECT_TRUE((result
== MIDI_OK
) || (result
== MIDI_INITIALIZATION_ERROR
));
262 EXPECT_EQ(MIDI_OK
, result
);