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.
4
5#include <string.h>
6
7#include "base/memory/scoped_ptr.h"
8#include "base/memory/weak_ptr.h"
9#include "content/browser/gamepad/gamepad_test_helpers.h"
10#include "content/browser/renderer_host/pepper/browser_ppapi_host_test.h"
11#include "content/browser/renderer_host/pepper/pepper_gamepad_host.h"
12#include "content/common/gamepad_hardware_buffer.h"
13#include "ppapi/c/pp_errors.h"
14#include "ppapi/host/host_message_context.h"
15#include "ppapi/proxy/gamepad_resource.h"
16#include "ppapi/proxy/ppapi_messages.h"
17#include "ppapi/proxy/resource_message_params.h"
18#include "ppapi/shared_impl/ppb_gamepad_shared.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace content {
22
23namespace {
24
25class PepperGamepadHostTest : public testing::Test,
26                              public BrowserPpapiHostTest {
27 public:
28  PepperGamepadHostTest() {}
29  virtual ~PepperGamepadHostTest() {}
30
31  void ConstructService(const blink::WebGamepads& test_data) {
32    service_.reset(new GamepadServiceTestConstructor(test_data));
33  }
34
35  GamepadService* gamepad_service() { return service_->gamepad_service(); }
36
37 protected:
38  scoped_ptr<GamepadServiceTestConstructor> service_;
39
40  DISALLOW_COPY_AND_ASSIGN(PepperGamepadHostTest);
41};
42
43inline ptrdiff_t AddressDiff(const void* a, const void* b) {
44  return static_cast<const char*>(a) - static_cast<const char*>(b);
45}
46
47}  // namespace
48
49// Validate the memory layout of the Pepper proxy struct matches the content
50// one. The proxy can't depend on content so has a duplicate definition. This
51// code can see both definitions so we do the validation here.
52TEST_F(PepperGamepadHostTest, ValidateHardwareBuffersMatch) {
53  // Hardware buffer.
54  COMPILE_ASSERT(sizeof(ppapi::ContentGamepadHardwareBuffer) ==
55                     sizeof(GamepadHardwareBuffer),
56                 gamepad_hardware_buffers_must_match);
57  ppapi::ContentGamepadHardwareBuffer ppapi_buf;
58  GamepadHardwareBuffer content_buf;
59  EXPECT_EQ(AddressDiff(&content_buf.sequence, &content_buf),
60            AddressDiff(&ppapi_buf.sequence, &ppapi_buf));
61  EXPECT_EQ(AddressDiff(&content_buf.buffer, &content_buf),
62            AddressDiff(&ppapi_buf.buffer, &ppapi_buf));
63}
64
65TEST_F(PepperGamepadHostTest, ValidateGamepadsMatch) {
66  // Gamepads.
67  COMPILE_ASSERT(sizeof(ppapi::WebKitGamepads) == sizeof(blink::WebGamepads),
68                 gamepads_data_must_match);
69  ppapi::WebKitGamepads ppapi_gamepads;
70  blink::WebGamepads web_gamepads;
71  EXPECT_EQ(AddressDiff(&web_gamepads.length, &web_gamepads),
72            AddressDiff(&ppapi_gamepads.length, &ppapi_gamepads));
73
74  // See comment below on storage & the EXPECT macro.
75  size_t webkit_items_length_cap = blink::WebGamepads::itemsLengthCap;
76  size_t ppapi_items_length_cap = ppapi::WebKitGamepads::kItemsLengthCap;
77  EXPECT_EQ(webkit_items_length_cap, ppapi_items_length_cap);
78
79  for (size_t i = 0; i < web_gamepads.itemsLengthCap; i++) {
80    EXPECT_EQ(AddressDiff(&web_gamepads.items[0], &web_gamepads),
81              AddressDiff(&ppapi_gamepads.items[0], &ppapi_gamepads));
82  }
83}
84
85TEST_F(PepperGamepadHostTest, ValidateGamepadMatch) {
86  // Gamepad.
87  COMPILE_ASSERT(sizeof(ppapi::WebKitGamepad) == sizeof(blink::WebGamepad),
88                 gamepad_data_must_match);
89  ppapi::WebKitGamepad ppapi_gamepad;
90  blink::WebGamepad web_gamepad;
91
92  // Using EXPECT seems to force storage for the parameter, which the constants
93  // in the WebKit/PPAPI headers don't have. So we have to use temporaries
94  // before comparing them.
95  size_t webkit_id_length_cap = blink::WebGamepad::idLengthCap;
96  size_t ppapi_id_length_cap = ppapi::WebKitGamepad::kIdLengthCap;
97  EXPECT_EQ(webkit_id_length_cap, ppapi_id_length_cap);
98
99  size_t webkit_axes_length_cap = blink::WebGamepad::axesLengthCap;
100  size_t ppapi_axes_length_cap = ppapi::WebKitGamepad::kAxesLengthCap;
101  EXPECT_EQ(webkit_axes_length_cap, ppapi_axes_length_cap);
102
103  size_t webkit_buttons_length_cap = blink::WebGamepad::buttonsLengthCap;
104  size_t ppapi_buttons_length_cap = ppapi::WebKitGamepad::kButtonsLengthCap;
105  EXPECT_EQ(webkit_buttons_length_cap, ppapi_buttons_length_cap);
106
107  EXPECT_EQ(AddressDiff(&web_gamepad.connected, &web_gamepad),
108            AddressDiff(&ppapi_gamepad.connected, &ppapi_gamepad));
109  EXPECT_EQ(AddressDiff(&web_gamepad.id, &web_gamepad),
110            AddressDiff(&ppapi_gamepad.id, &ppapi_gamepad));
111  EXPECT_EQ(AddressDiff(&web_gamepad.timestamp, &web_gamepad),
112            AddressDiff(&ppapi_gamepad.timestamp, &ppapi_gamepad));
113  EXPECT_EQ(AddressDiff(&web_gamepad.axesLength, &web_gamepad),
114            AddressDiff(&ppapi_gamepad.axes_length, &ppapi_gamepad));
115  EXPECT_EQ(AddressDiff(&web_gamepad.axes, &web_gamepad),
116            AddressDiff(&ppapi_gamepad.axes, &ppapi_gamepad));
117  EXPECT_EQ(AddressDiff(&web_gamepad.buttonsLength, &web_gamepad),
118            AddressDiff(&ppapi_gamepad.buttons_length, &ppapi_gamepad));
119  EXPECT_EQ(AddressDiff(&web_gamepad.buttons, &web_gamepad),
120            AddressDiff(&ppapi_gamepad.buttons, &ppapi_gamepad));
121}
122
123TEST_F(PepperGamepadHostTest, WaitForReply) {
124  blink::WebGamepads default_data;
125  memset(&default_data, 0, sizeof(blink::WebGamepads));
126  default_data.length = 1;
127  default_data.items[0].connected = true;
128  default_data.items[0].buttonsLength = 1;
129  ConstructService(default_data);
130
131  PP_Instance pp_instance = 12345;
132  PP_Resource pp_resource = 67890;
133  PepperGamepadHost gamepad_host(
134      gamepad_service(), GetBrowserPpapiHost(), pp_instance, pp_resource);
135
136  // Synthesize a request for gamepad data.
137  ppapi::host::HostMessageContext context(
138      ppapi::proxy::ResourceMessageCallParams(pp_resource, 1));
139  EXPECT_EQ(PP_OK_COMPLETIONPENDING,
140            gamepad_host.OnResourceMessageReceived(
141                PpapiHostMsg_Gamepad_RequestMemory(), &context));
142
143  MockGamepadDataFetcher* fetcher = service_->data_fetcher();
144  fetcher->WaitForDataReadAndCallbacksIssued();
145
146  // It should not have sent the callback message.
147  service_->message_loop().RunUntilIdle();
148  EXPECT_EQ(0u, sink().message_count());
149
150  // Set a button down and wait for it to be read twice.
151  blink::WebGamepads button_down_data = default_data;
152  button_down_data.items[0].buttons[0].value = 1.f;
153  button_down_data.items[0].buttons[0].pressed = true;
154  fetcher->SetTestData(button_down_data);
155  fetcher->WaitForDataReadAndCallbacksIssued();
156
157  // It should have sent a callback.
158  service_->message_loop().RunUntilIdle();
159  ppapi::proxy::ResourceMessageReplyParams reply_params;
160  IPC::Message reply_msg;
161  ASSERT_TRUE(sink().GetFirstResourceReplyMatching(
162      PpapiPluginMsg_Gamepad_SendMemory::ID, &reply_params, &reply_msg));
163
164  // Extract the shared memory handle.
165  base::SharedMemoryHandle reply_handle;
166  EXPECT_TRUE(reply_params.TakeSharedMemoryHandleAtIndex(0, &reply_handle));
167
168  // Validate the shared memory.
169  base::SharedMemory shared_memory(reply_handle, true);
170  EXPECT_TRUE(shared_memory.Map(sizeof(ppapi::ContentGamepadHardwareBuffer)));
171  const ppapi::ContentGamepadHardwareBuffer* buffer =
172      static_cast<const ppapi::ContentGamepadHardwareBuffer*>(
173          shared_memory.memory());
174  EXPECT_EQ(button_down_data.length, buffer->buffer.length);
175  EXPECT_EQ(button_down_data.items[0].buttonsLength,
176            buffer->buffer.items[0].buttons_length);
177  for (size_t i = 0; i < ppapi::WebKitGamepad::kButtonsLengthCap; i++) {
178    EXPECT_EQ(button_down_data.items[0].buttons[i].value,
179              buffer->buffer.items[0].buttons[i].value);
180    EXPECT_EQ(button_down_data.items[0].buttons[i].pressed,
181              buffer->buffer.items[0].buttons[i].pressed);
182  }
183
184  // Duplicate requests should be denied.
185  EXPECT_EQ(PP_ERROR_FAILED,
186            gamepad_host.OnResourceMessageReceived(
187                PpapiHostMsg_Gamepad_RequestMemory(), &context));
188}
189
190}  // namespace content
191