1 // Copyright (c) 2012 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 "base/basictypes.h"
6 #include "base/compiler_specific.h"
7 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/proxy/connection.h"
9 #include "ppapi/proxy/device_enumeration_resource_helper.h"
10 #include "ppapi/proxy/plugin_resource.h"
11 #include "ppapi/proxy/plugin_resource_tracker.h"
12 #include "ppapi/proxy/plugin_var_tracker.h"
13 #include "ppapi/proxy/ppapi_message_utils.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/proxy/ppapi_proxy_test.h"
16 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
17 #include "ppapi/shared_impl/var.h"
18 #include "ppapi/thunk/enter.h"
19 #include "ppapi/thunk/ppb_device_ref_api.h"
20 #include "ppapi/thunk/thunk.h"
27 typedef PluginProxyTest DeviceEnumerationResourceHelperTest
;
29 Connection
GetConnection(PluginProxyTestHarness
* harness
) {
30 CHECK(harness
->GetGlobals()->IsPluginGlobals());
33 static_cast<PluginGlobals
*>(harness
->GetGlobals())->GetBrowserSender(),
34 harness
->plugin_dispatcher());
37 bool CompareDeviceRef(PluginVarTracker
* var_tracker
,
39 const DeviceRefData
& expected
) {
40 thunk::EnterResource
<thunk::PPB_DeviceRef_API
> enter(resource
, true);
44 if (expected
.type
!= enter
.object()->GetType())
47 PP_Var name_pp_var
= enter
.object()->GetName();
50 Var
* name_var
= var_tracker
->GetVar(name_pp_var
);
53 StringVar
* name_string_var
= name_var
->AsStringVar();
56 if (expected
.name
!= name_string_var
->value())
61 var_tracker
->ReleaseVar(name_pp_var
);
65 class TestResource
: public PluginResource
{
67 TestResource(Connection connection
, PP_Instance instance
)
68 : PluginResource(connection
, instance
),
69 ALLOW_THIS_IN_INITIALIZER_LIST(device_enumeration_(this)) {
72 virtual ~TestResource() {}
74 virtual void OnReplyReceived(const ResourceMessageReplyParams
& params
,
75 const IPC::Message
& msg
) OVERRIDE
{
76 if (!device_enumeration_
.HandleReply(params
, msg
))
77 PluginResource::OnReplyReceived(params
, msg
);
80 DeviceEnumerationResourceHelper
& device_enumeration() {
81 return device_enumeration_
;
85 DeviceEnumerationResourceHelper device_enumeration_
;
87 DISALLOW_COPY_AND_ASSIGN(TestResource
);
92 TestCallback() : called_(false), result_(PP_ERROR_FAILED
) {
98 PP_CompletionCallback
MakeCompletionCallback() {
99 return PP_MakeCompletionCallback(&CompletionCallbackBody
, this);
102 bool called() const { return called_
; }
103 int32_t result() const { return result_
; }
106 static void CompletionCallbackBody(void* user_data
, int32_t result
) {
107 TestCallback
* callback
= static_cast<TestCallback
*>(user_data
);
109 CHECK(!callback
->called_
);
110 callback
->called_
= true;
111 callback
->result_
= result
;
117 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
120 class TestArrayOutput
{
122 explicit TestArrayOutput(PluginResourceTracker
* resource_tracker
)
125 resource_tracker_(resource_tracker
) {
130 for (size_t i
= 0; i
< count_
; ++i
)
131 resource_tracker_
->ReleaseResource(data_
[i
]);
136 PP_ArrayOutput
MakeArrayOutput() {
137 PP_ArrayOutput array_output
= { &GetDataBuffer
, this };
141 const PP_Resource
* data() const { return data_
; }
142 uint32_t count() const { return count_
; }
145 static void* GetDataBuffer(void* user_data
,
146 uint32_t element_count
,
147 uint32_t element_size
) {
148 CHECK_EQ(element_size
, sizeof(PP_Resource
));
150 TestArrayOutput
* output
= static_cast<TestArrayOutput
*>(user_data
);
151 CHECK(!output
->data_
);
153 output
->count_
= element_count
;
154 if (element_count
> 0)
155 output
->data_
= new PP_Resource
[element_count
];
157 output
->data_
= NULL
;
159 return output
->data_
;
164 PluginResourceTracker
* resource_tracker_
;
166 DISALLOW_COPY_AND_ASSIGN(TestArrayOutput
);
169 class TestMonitorDeviceChange
{
171 explicit TestMonitorDeviceChange(PluginVarTracker
* var_tracker
)
173 same_as_expected_(false),
174 var_tracker_(var_tracker
) {
177 ~TestMonitorDeviceChange() {}
179 void SetExpectedResult(const std::vector
<DeviceRefData
>& expected
) {
181 same_as_expected_
= false;
182 expected_
= expected
;
185 bool called() const { return called_
; }
187 bool same_as_expected() const { return same_as_expected_
; }
189 static void MonitorDeviceChangeCallback(void* user_data
,
190 uint32_t device_count
,
191 const PP_Resource devices
[]) {
192 TestMonitorDeviceChange
* helper
=
193 static_cast<TestMonitorDeviceChange
*>(user_data
);
194 CHECK(!helper
->called_
);
196 helper
->called_
= true;
197 helper
->same_as_expected_
= false;
198 if (device_count
!= helper
->expected_
.size())
200 for (size_t i
= 0; i
< device_count
; ++i
) {
201 if (!CompareDeviceRef(helper
->var_tracker_
, devices
[i
],
202 helper
->expected_
[i
])) {
206 helper
->same_as_expected_
= true;
211 bool same_as_expected_
;
212 std::vector
<DeviceRefData
> expected_
;
213 PluginVarTracker
* var_tracker_
;
215 DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange
);
220 TEST_F(DeviceEnumerationResourceHelperTest
, EnumerateDevices
) {
221 scoped_refptr
<TestResource
> resource(
222 new TestResource(GetConnection(this), pp_instance()));
223 DeviceEnumerationResourceHelper
& device_enumeration
=
224 resource
->device_enumeration();
226 TestArrayOutput
output(&resource_tracker());
227 TestCallback callback
;
228 scoped_refptr
<TrackedCallback
> tracked_callback(
229 new TrackedCallback(resource
.get(), callback
.MakeCompletionCallback()));
230 int32_t result
= device_enumeration
.EnumerateDevices(output
.MakeArrayOutput(),
232 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
234 // Should have sent an EnumerateDevices message.
235 ResourceMessageCallParams params
;
237 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
238 PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID
, ¶ms
, &msg
));
240 // Synthesize a response.
241 ResourceMessageReplyParams
reply_params(params
.pp_resource(),
243 reply_params
.set_result(PP_OK
);
244 std::vector
<DeviceRefData
> data
;
245 DeviceRefData data_item
;
246 data_item
.type
= PP_DEVICETYPE_DEV_AUDIOCAPTURE
;
247 data_item
.name
= "name_1";
248 data_item
.id
= "id_1";
249 data
.push_back(data_item
);
250 data_item
.type
= PP_DEVICETYPE_DEV_VIDEOCAPTURE
;
251 data_item
.name
= "name_2";
252 data_item
.id
= "id_2";
253 data
.push_back(data_item
);
255 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
256 PpapiPluginMsg_ResourceReply(
258 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(data
))));
260 EXPECT_TRUE(callback
.called());
261 EXPECT_EQ(PP_OK
, callback
.result());
262 EXPECT_EQ(2U, output
.count());
263 for (size_t i
= 0; i
< output
.count(); ++i
)
264 EXPECT_TRUE(CompareDeviceRef(&var_tracker(), output
.data()[i
], data
[i
]));
267 TEST_F(DeviceEnumerationResourceHelperTest
, MonitorDeviceChange
) {
268 scoped_refptr
<TestResource
> resource(
269 new TestResource(GetConnection(this), pp_instance()));
270 DeviceEnumerationResourceHelper
& device_enumeration
=
271 resource
->device_enumeration();
273 TestMonitorDeviceChange
helper(&var_tracker());
275 int32_t result
= device_enumeration
.MonitorDeviceChange(
276 &TestMonitorDeviceChange::MonitorDeviceChangeCallback
, &helper
);
277 ASSERT_EQ(PP_OK
, result
);
279 // Should have sent a MonitorDeviceChange message.
280 ResourceMessageCallParams params
;
282 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
283 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID
, ¶ms
, &msg
));
284 sink().ClearMessages();
286 uint32_t callback_id
= 0;
287 ASSERT_TRUE(UnpackMessage
<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange
>(
290 ResourceMessageReplyParams
reply_params(params
.pp_resource(), 0);
291 reply_params
.set_result(PP_OK
);
292 std::vector
<DeviceRefData
> data
;
294 helper
.SetExpectedResult(data
);
296 // Synthesize a response with no device.
297 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
298 PpapiPluginMsg_ResourceReply(
300 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
301 callback_id
, data
))));
302 EXPECT_TRUE(helper
.called() && helper
.same_as_expected());
304 DeviceRefData data_item
;
305 data_item
.type
= PP_DEVICETYPE_DEV_AUDIOCAPTURE
;
306 data_item
.name
= "name_1";
307 data_item
.id
= "id_1";
308 data
.push_back(data_item
);
309 data_item
.type
= PP_DEVICETYPE_DEV_VIDEOCAPTURE
;
310 data_item
.name
= "name_2";
311 data_item
.id
= "id_2";
312 data
.push_back(data_item
);
314 helper
.SetExpectedResult(data
);
316 // Synthesize a response with some devices.
317 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
318 PpapiPluginMsg_ResourceReply(
320 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
321 callback_id
, data
))));
322 EXPECT_TRUE(helper
.called() && helper
.same_as_expected());
324 TestMonitorDeviceChange
helper2(&var_tracker());
326 result
= device_enumeration
.MonitorDeviceChange(
327 &TestMonitorDeviceChange::MonitorDeviceChangeCallback
, &helper2
);
328 ASSERT_EQ(PP_OK
, result
);
330 // Should have sent another MonitorDeviceChange message.
331 ResourceMessageCallParams params2
;
333 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
334 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID
, ¶ms2
, &msg2
));
335 sink().ClearMessages();
337 uint32_t callback_id2
= 0;
338 ASSERT_TRUE(UnpackMessage
<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange
>(
339 msg2
, &callback_id2
));
341 helper
.SetExpectedResult(data
);
342 helper2
.SetExpectedResult(data
);
343 // |helper2| should receive the result while |helper| shouldn't.
344 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
345 PpapiPluginMsg_ResourceReply(
347 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
348 callback_id2
, data
))));
349 EXPECT_TRUE(helper2
.called() && helper2
.same_as_expected());
350 EXPECT_FALSE(helper
.called());
352 helper
.SetExpectedResult(data
);
353 helper2
.SetExpectedResult(data
);
354 // Even if a message with |callback_id| arrives. |helper| shouldn't receive
356 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
357 PpapiPluginMsg_ResourceReply(
359 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
360 callback_id
, data
))));
361 EXPECT_FALSE(helper2
.called());
362 EXPECT_FALSE(helper
.called());
364 result
= device_enumeration
.MonitorDeviceChange(NULL
, NULL
);
365 ASSERT_EQ(PP_OK
, result
);
367 // Should have sent a StopMonitoringDeviceChange message.
368 ResourceMessageCallParams params3
;
370 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
371 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID
,
373 sink().ClearMessages();
375 helper2
.SetExpectedResult(data
);
376 // |helper2| shouldn't receive any result any more.
377 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
378 PpapiPluginMsg_ResourceReply(
380 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
381 callback_id2
, data
))));
382 EXPECT_FALSE(helper2
.called());