Index: ppapi/proxy/device_enumeration_resource_helper_unittest.cc |
diff --git a/ppapi/proxy/device_enumeration_resource_helper_unittest.cc b/ppapi/proxy/device_enumeration_resource_helper_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..330bca3e3b96668ad4ccd0b41332af24972433b9 |
--- /dev/null |
+++ b/ppapi/proxy/device_enumeration_resource_helper_unittest.cc |
@@ -0,0 +1,386 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/basictypes.h" |
+#include "base/compiler_specific.h" |
+#include "ppapi/c/pp_errors.h" |
+#include "ppapi/proxy/connection.h" |
+#include "ppapi/proxy/device_enumeration_resource_helper.h" |
+#include "ppapi/proxy/plugin_resource.h" |
+#include "ppapi/proxy/plugin_resource_tracker.h" |
+#include "ppapi/proxy/plugin_var_tracker.h" |
+#include "ppapi/proxy/ppapi_message_utils.h" |
+#include "ppapi/proxy/ppapi_messages.h" |
+#include "ppapi/proxy/ppapi_proxy_test.h" |
+#include "ppapi/shared_impl/ppb_device_ref_shared.h" |
+#include "ppapi/shared_impl/var.h" |
+#include "ppapi/thunk/enter.h" |
+#include "ppapi/thunk/ppb_device_ref_api.h" |
+#include "ppapi/thunk/thunk.h" |
+ |
+namespace ppapi { |
+namespace proxy { |
+ |
+namespace { |
+ |
+typedef PluginProxyTest DeviceEnumerationResourceHelperTest; |
+ |
+Connection GetConnection(PluginProxyTestHarness* harness) { |
+ CHECK(harness->GetGlobals()->IsPluginGlobals()); |
+ |
+ return Connection( |
+ static_cast<PluginGlobals*>(harness->GetGlobals())->GetBrowserSender(), |
+ harness->plugin_dispatcher()); |
+} |
+ |
+bool CompareDeviceRef(PluginVarTracker* var_tracker, |
+ PP_Resource resource, |
+ const DeviceRefData& expected) { |
+ thunk::EnterResource<thunk::PPB_DeviceRef_API> enter(resource, true); |
+ if (enter.failed()) |
+ return false; |
+ |
+ if (expected.type != enter.object()->GetType()) |
+ return false; |
+ |
+ PP_Var name_pp_var = enter.object()->GetName(); |
+ bool result = false; |
+ do { |
+ Var* name_var = var_tracker->GetVar(name_pp_var); |
+ if (!name_var) |
+ break; |
+ StringVar* name_string_var = name_var->AsStringVar(); |
+ if (!name_string_var) |
+ break; |
+ if (expected.name != name_string_var->value()) |
+ break; |
+ |
+ result = true; |
+ } while (false); |
+ var_tracker->ReleaseVar(name_pp_var); |
+ return result; |
+} |
+ |
+class TestResource : public PluginResource { |
+ public: |
+ TestResource(Connection connection, PP_Instance instance) |
+ : PluginResource(connection, instance), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(device_enumeration_(this)) { |
+ } |
+ |
+ virtual ~TestResource() {} |
+ |
+ virtual void OnReplyReceived(const ResourceMessageReplyParams& params, |
+ const IPC::Message& msg) OVERRIDE { |
+ if (!device_enumeration_.HandleReply(params, msg)) |
+ PluginResource::OnReplyReceived(params, msg); |
+ } |
+ |
+ DeviceEnumerationResourceHelper& device_enumeration() { |
+ return device_enumeration_; |
+ } |
+ |
+ private: |
+ DeviceEnumerationResourceHelper device_enumeration_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestResource); |
+}; |
+ |
+class TestCallback { |
+ public: |
+ TestCallback() : called_(false), result_(PP_ERROR_FAILED) { |
+ } |
+ ~TestCallback() { |
+ CHECK(called_); |
+ } |
+ |
+ PP_CompletionCallback MakeCompletionCallback() { |
+ return PP_MakeCompletionCallback(&CompletionCallbackBody, this); |
+ } |
+ |
+ bool called() const { return called_; } |
+ int32_t result() const { return result_; } |
+ |
+ private: |
+ static void CompletionCallbackBody(void* user_data, int32_t result) { |
+ TestCallback* callback = static_cast<TestCallback*>(user_data); |
+ |
+ CHECK(!callback->called_); |
+ callback->called_ = true; |
+ callback->result_ = result; |
+ } |
+ |
+ bool called_; |
+ int32_t result_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestCallback); |
+}; |
+ |
+class TestArrayOutput { |
+ public: |
+ explicit TestArrayOutput(PluginResourceTracker* resource_tracker) |
+ : data_(NULL), |
+ count_(0), |
+ resource_tracker_(resource_tracker) { |
+ } |
+ |
+ ~TestArrayOutput() { |
+ if (count_ > 0) { |
+ for (size_t i = 0; i < count_; ++i) |
+ resource_tracker_->ReleaseResource(data_[i]); |
+ delete [] data_; |
+ } |
+ } |
+ |
+ PP_ArrayOutput MakeArrayOutput() { |
+ PP_ArrayOutput array_output = { &GetDataBuffer, this }; |
+ return array_output; |
+ } |
+ |
+ const PP_Resource* data() const { return data_; } |
+ uint32_t count() const { return count_; } |
+ |
+ private: |
+ static void* GetDataBuffer(void* user_data, |
+ uint32_t element_count, |
+ uint32_t element_size) { |
+ CHECK_EQ(element_size, sizeof(PP_Resource)); |
+ |
+ TestArrayOutput* output = static_cast<TestArrayOutput*>(user_data); |
+ CHECK(!output->data_); |
+ |
+ output->count_ = element_count; |
+ if (element_count > 0) |
+ output->data_ = new PP_Resource[element_count]; |
+ else |
+ output->data_ = NULL; |
+ |
+ return output->data_; |
+ } |
+ |
+ PP_Resource* data_; |
+ uint32_t count_; |
+ PluginResourceTracker* resource_tracker_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestArrayOutput); |
+}; |
+ |
+class TestMonitorDeviceChange { |
+ public: |
+ explicit TestMonitorDeviceChange(PluginVarTracker* var_tracker) |
+ : called_(false), |
+ same_as_expected_(false), |
+ var_tracker_(var_tracker) { |
+ } |
+ |
+ ~TestMonitorDeviceChange() {} |
+ |
+ void SetExpectedResult(const std::vector<DeviceRefData>& expected) { |
+ called_ = false; |
+ same_as_expected_ = false; |
+ expected_ = expected; |
+ } |
+ |
+ bool called() const { return called_; } |
+ |
+ bool same_as_expected() const { return same_as_expected_; } |
+ |
+ static void MonitorDeviceChangeCallback(void* user_data, |
+ uint32_t device_count, |
+ const PP_Resource devices[]) { |
+ TestMonitorDeviceChange* helper = |
+ static_cast<TestMonitorDeviceChange*>(user_data); |
+ CHECK(!helper->called_); |
+ |
+ helper->called_ = true; |
+ helper->same_as_expected_ = false; |
+ if (device_count != helper->expected_.size()) |
+ return; |
+ for (size_t i = 0; i < device_count; ++i) { |
+ if (!CompareDeviceRef(helper->var_tracker_, devices[i], |
+ helper->expected_[i])) { |
+ return; |
+ } |
+ } |
+ helper->same_as_expected_ = true; |
+ } |
+ |
+ private: |
+ bool called_; |
+ bool same_as_expected_; |
+ std::vector<DeviceRefData> expected_; |
+ PluginVarTracker* var_tracker_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange); |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(DeviceEnumerationResourceHelperTest, EnumerateDevices) { |
+ scoped_refptr<TestResource> resource( |
+ new TestResource(GetConnection(this), pp_instance())); |
+ DeviceEnumerationResourceHelper& device_enumeration = |
+ resource->device_enumeration(); |
+ |
+ TestArrayOutput output(&resource_tracker()); |
+ TestCallback callback; |
+ scoped_refptr<TrackedCallback> tracked_callback( |
+ new TrackedCallback(resource.get(), callback.MakeCompletionCallback())); |
+ int32_t result = device_enumeration.EnumerateDevices(output.MakeArrayOutput(), |
+ tracked_callback); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
+ |
+ // Should have sent an EnumerateDevices message. |
+ ResourceMessageCallParams params; |
+ IPC::Message msg; |
+ ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID, ¶ms, &msg)); |
+ |
+ // Synthesize a response. |
+ ResourceMessageReplyParams reply_params(params.pp_resource(), |
+ params.sequence()); |
+ reply_params.set_result(PP_OK); |
+ std::vector<DeviceRefData> data; |
+ DeviceRefData data_item; |
+ data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; |
+ data_item.name = "name_1"; |
+ data_item.id = "id_1"; |
+ data.push_back(data_item); |
+ data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; |
+ data_item.name = "name_2"; |
+ data_item.id = "id_2"; |
+ data.push_back(data_item); |
+ |
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
+ PpapiPluginMsg_ResourceReply( |
+ reply_params, |
+ PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(data)))); |
+ |
+ EXPECT_TRUE(callback.called()); |
+ EXPECT_EQ(PP_OK, callback.result()); |
+ EXPECT_EQ(2U, output.count()); |
+ for (size_t i = 0; i < output.count(); ++i) |
+ EXPECT_TRUE(CompareDeviceRef(&var_tracker(), output.data()[i], data[i])); |
+} |
+ |
+TEST_F(DeviceEnumerationResourceHelperTest, MonitorDeviceChange) { |
+ scoped_refptr<TestResource> resource( |
+ new TestResource(GetConnection(this), pp_instance())); |
+ DeviceEnumerationResourceHelper& device_enumeration = |
+ resource->device_enumeration(); |
+ |
+ TestMonitorDeviceChange helper(&var_tracker()); |
+ |
+ int32_t result = device_enumeration.MonitorDeviceChange( |
+ &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper); |
+ ASSERT_EQ(PP_OK, result); |
+ |
+ // Should have sent a MonitorDeviceChange message. |
+ ResourceMessageCallParams params; |
+ IPC::Message msg; |
+ ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms, &msg)); |
+ sink().ClearMessages(); |
+ |
+ uint32_t callback_id = 0; |
+ ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>( |
+ msg, &callback_id)); |
+ |
+ ResourceMessageReplyParams reply_params(params.pp_resource(), 0); |
+ reply_params.set_result(PP_OK); |
+ std::vector<DeviceRefData> data; |
+ |
+ helper.SetExpectedResult(data); |
+ |
+ // Synthesize a response with no device. |
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
+ PpapiPluginMsg_ResourceReply( |
+ reply_params, |
+ PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
+ callback_id, data)))); |
+ EXPECT_TRUE(helper.called() && helper.same_as_expected()); |
+ |
+ DeviceRefData data_item; |
+ data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; |
+ data_item.name = "name_1"; |
+ data_item.id = "id_1"; |
+ data.push_back(data_item); |
+ data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; |
+ data_item.name = "name_2"; |
+ data_item.id = "id_2"; |
+ data.push_back(data_item); |
+ |
+ helper.SetExpectedResult(data); |
+ |
+ // Synthesize a response with some devices. |
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
+ PpapiPluginMsg_ResourceReply( |
+ reply_params, |
+ PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
+ callback_id, data)))); |
+ EXPECT_TRUE(helper.called() && helper.same_as_expected()); |
+ |
+ TestMonitorDeviceChange helper2(&var_tracker()); |
+ |
+ result = device_enumeration.MonitorDeviceChange( |
+ &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper2); |
+ ASSERT_EQ(PP_OK, result); |
+ |
+ // Should have sent another MonitorDeviceChange message. |
+ ResourceMessageCallParams params2; |
+ IPC::Message msg2; |
+ ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms2, &msg2)); |
+ sink().ClearMessages(); |
+ |
+ uint32_t callback_id2 = 0; |
+ ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>( |
+ msg2, &callback_id2)); |
+ |
+ helper.SetExpectedResult(data); |
+ helper2.SetExpectedResult(data); |
+ // |helper2| should receive the result while |helper| shouldn't. |
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
+ PpapiPluginMsg_ResourceReply( |
+ reply_params, |
+ PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
+ callback_id2, data)))); |
+ EXPECT_TRUE(helper2.called() && helper2.same_as_expected()); |
+ EXPECT_FALSE(helper.called()); |
+ |
+ helper.SetExpectedResult(data); |
+ helper2.SetExpectedResult(data); |
+ // Even if a message with |callback_id| arrives. |helper| shouldn't receive |
+ // the result. |
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
+ PpapiPluginMsg_ResourceReply( |
+ reply_params, |
+ PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
+ callback_id, data)))); |
+ EXPECT_FALSE(helper2.called()); |
+ EXPECT_FALSE(helper.called()); |
+ |
+ result = device_enumeration.MonitorDeviceChange(NULL, NULL); |
+ ASSERT_EQ(PP_OK, result); |
+ |
+ // Should have sent a StopMonitoringDeviceChange message. |
+ ResourceMessageCallParams params3; |
+ IPC::Message msg3; |
+ ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID, |
+ ¶ms3, &msg3)); |
+ sink().ClearMessages(); |
+ |
+ helper2.SetExpectedResult(data); |
+ // |helper2| shouldn't receive any result any more. |
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
+ PpapiPluginMsg_ResourceReply( |
+ reply_params, |
+ PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
+ callback_id2, data)))); |
+ EXPECT_FALSE(helper2.called()); |
+} |
+ |
+} // namespace proxy |
+} // namespace ppapi |