VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/testcase/tstUsbMouse.cpp@ 86399

Last change on this file since 86399 was 86399, checked in by vboxsync, 4 years ago

tstUsbMouse: Don't leak the CFGM tree for each test instance. bugref:9841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1/* $Id: tstUsbMouse.cpp 86399 2020-10-01 19:47:17Z vboxsync $ */
2/** @file
3 * tstUsbMouse.cpp - testcase USB mouse and tablet devices.
4 */
5
6/*
7 * Copyright (C) 2013-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "VBoxDD.h"
23#include <VBox/vmm/pdmdrv.h>
24#include <iprt/mem.h>
25#include <iprt/rand.h>
26#include <iprt/stream.h>
27#include <iprt/test.h>
28#include <iprt/uuid.h>
29
30
31/*********************************************************************************************************************************
32* Structures and Typedefs *
33*********************************************************************************************************************************/
34/** Test mouse driver structure. */
35typedef struct DRVTSTMOUSE
36{
37 /** The USBHID structure. */
38 struct USBHID *pUsbHid;
39 /** The base interface for the mouse driver. */
40 PDMIBASE IBase;
41 /** Our mouse connector interface. */
42 PDMIMOUSECONNECTOR IConnector;
43 /** The base interface of the attached mouse port. */
44 PPDMIBASE pDrvBase;
45 /** The mouse port interface of the attached mouse port. */
46 PPDMIMOUSEPORT pDrv;
47 /** Is relative mode currently supported? */
48 bool fRel;
49 /** Is absolute mode currently supported? */
50 bool fAbs;
51 /** Is multi-touch mode currently supported? */
52 bool fMT;
53} DRVTSTMOUSE;
54typedef DRVTSTMOUSE *PDRVTSTMOUSE;
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60static PDMUSBHLP g_tstUsbHlp;
61/** Global mouse driver variable.
62 * @todo To be improved some time. */
63static DRVTSTMOUSE g_drvTstMouse;
64
65
66/** @interface_method_impl{PDMUSBHLPR3,pfnVMSetErrorV} */
67static DECLCALLBACK(int) tstVMSetErrorV(PPDMUSBINS pUsbIns, int rc,
68 RT_SRC_POS_DECL, const char *pszFormat,
69 va_list va)
70{
71 RT_NOREF(pUsbIns);
72 RTPrintf("Error: %s:%u:%s:", RT_SRC_POS_ARGS);
73 RTPrintfV(pszFormat, va);
74 return rc;
75}
76
77/** @interface_method_impl{PDMUSBHLPR3,pfnDriverAttach} */
78/** @todo We currently just take the driver interface from the global
79 * variable. This is sufficient for a unit test but still a bit sad. */
80static DECLCALLBACK(int) tstDriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
81 PPDMIBASE *ppBaseInterface, const char *pszDesc)
82{
83 RT_NOREF3(pUsbIns, iLun, pszDesc);
84 g_drvTstMouse.pDrvBase = pBaseInterface;
85 g_drvTstMouse.pDrv = PDMIBASE_QUERY_INTERFACE(pBaseInterface, PDMIMOUSEPORT);
86 *ppBaseInterface = &g_drvTstMouse.IBase;
87 return VINF_SUCCESS;
88}
89
90
91/**
92 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
93 */
94static DECLCALLBACK(void *) tstMouseQueryInterface(PPDMIBASE pInterface,
95 const char *pszIID)
96{
97 PDRVTSTMOUSE pUsbIns = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IBase);
98 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pUsbIns->IBase);
99 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pUsbIns->IConnector);
100 return NULL;
101}
102
103
104/**
105 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
106 */
107static DECLCALLBACK(void) tstMouseReportModes(PPDMIMOUSECONNECTOR pInterface,
108 bool fRel, bool fAbs, bool fMT)
109{
110 PDRVTSTMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVTSTMOUSE, IConnector);
111 pDrv->fRel = fRel;
112 pDrv->fAbs = fAbs;
113 pDrv->fMT = fMT;
114}
115
116
117static int tstMouseConstruct(RTTEST hTest, int iInstance, const char *pcszMode,
118 uint8_t u8CoordShift, PPDMUSBINS *ppThis,
119 uint32_t uInstanceVersion = PDM_USBINS_VERSION)
120{
121 size_t cbUsbIns = RT_UOFFSETOF(PDMUSBINS, achInstanceData) + g_UsbHidMou.cbInstance;
122 PPDMUSBINS pUsbIns;
123 int rc = RTTestGuardedAlloc(hTest, cbUsbIns, 1, RTRandU32Ex(0, 1) != 0 /*fHead*/, (void **)&pUsbIns);
124 if (RT_SUCCESS(rc))
125 {
126 RT_BZERO(pUsbIns, cbUsbIns);
127
128 PCFGMNODE pCfg = CFGMR3CreateTree(NULL);
129 if (pCfg)
130 {
131 rc = CFGMR3InsertString(pCfg, "Mode", pcszMode);
132 if (RT_SUCCESS(rc))
133 rc = CFGMR3InsertInteger(pCfg, "CoordShift", u8CoordShift);
134 if (RT_SUCCESS(rc))
135 {
136 g_drvTstMouse.pDrv = NULL;
137 g_drvTstMouse.pDrvBase = NULL;
138 pUsbIns->u32Version = uInstanceVersion;
139 pUsbIns->iInstance = iInstance;
140 pUsbIns->pHlpR3 = &g_tstUsbHlp;
141 pUsbIns->pvInstanceDataR3 = pUsbIns->achInstanceData;
142 pUsbIns->pCfg = pCfg;
143 rc = g_UsbHidMou.pfnConstruct(pUsbIns, iInstance, pCfg, NULL);
144 if (RT_SUCCESS(rc))
145 {
146 *ppThis = pUsbIns;
147 return rc;
148 }
149 }
150 /* Failure */
151 CFGMR3DestroyTree(pCfg);
152 }
153 }
154 RTTestGuardedFree(hTest, pUsbIns);
155 return rc;
156}
157
158
159static void tstMouseDestruct(RTTEST hTest, PPDMUSBINS pUsbIns)
160{
161 if (pUsbIns)
162 {
163 g_UsbHidMou.pfnDestruct(pUsbIns);
164 CFGMR3DestroyTree(pUsbIns->pCfg);
165 RTTestGuardedFree(hTest, pUsbIns);
166 }
167}
168
169
170static void testConstructAndDestruct(RTTEST hTest)
171{
172 RTTestSub(hTest, "simple construction and destruction");
173
174 /*
175 * Normal check first.
176 */
177 PPDMUSBINS pUsbIns = NULL;
178 RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns), VINF_SUCCESS);
179 tstMouseDestruct(hTest, pUsbIns);
180
181 /*
182 * Modify the dev hlp version.
183 */
184 static struct
185 {
186 int rc;
187 uint32_t uInsVersion;
188 uint32_t uHlpVersion;
189 } const s_aVersionTests[] =
190 {
191 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, 0 },
192 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(0, 1, 0) },
193 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 0) },
194 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 1, 1) },
195 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(1, 0, 0) },
196 { VERR_PDM_USBHLPR3_VERSION_MISMATCH, PDM_USBINS_VERSION, PDM_USBHLP_VERSION - PDM_VERSION_MAKE(1, 0, 0) },
197 { VINF_SUCCESS, PDM_USBINS_VERSION, PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) },
198 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION },
199 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 0), PDM_USBHLP_VERSION },
200 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 1, 1), PDM_USBHLP_VERSION },
201 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION + PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION },
202 { VERR_PDM_USBINS_VERSION_MISMATCH, PDM_USBINS_VERSION - PDM_VERSION_MAKE(1, 0, 0), PDM_USBHLP_VERSION },
203 { VINF_SUCCESS, PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION },
204 { VINF_SUCCESS,
205 PDM_USBINS_VERSION + PDM_VERSION_MAKE(0, 0, 1), PDM_USBHLP_VERSION + PDM_VERSION_MAKE(0, 0, 1) },
206 };
207 bool const fSavedMayPanic = RTAssertSetMayPanic(false);
208 bool const fSavedQuiet = RTAssertSetQuiet(true);
209 for (unsigned i = 0; i < RT_ELEMENTS(s_aVersionTests); i++)
210 {
211 g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = s_aVersionTests[i].uHlpVersion;
212 pUsbIns = NULL;
213 RTTEST_CHECK_RC(hTest, tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns, s_aVersionTests[i].uInsVersion),
214 s_aVersionTests[i].rc);
215 tstMouseDestruct(hTest, pUsbIns);
216 }
217 RTAssertSetMayPanic(fSavedMayPanic);
218 RTAssertSetQuiet(fSavedQuiet);
219
220 g_tstUsbHlp.u32Version = g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION;
221}
222
223
224static void testSendPositionRel(RTTEST hTest)
225{
226 PPDMUSBINS pUsbIns = NULL;
227 VUSBURB Urb;
228 RTTestSub(hTest, "sending a relative position event");
229 int rc = tstMouseConstruct(hTest, 0, "relative", 1, &pUsbIns);
230 RT_ZERO(Urb);
231 if (RT_SUCCESS(rc))
232 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
233 if (RT_SUCCESS(rc) && !g_drvTstMouse.pDrv)
234 rc = VERR_PDM_MISSING_INTERFACE;
235 RTTEST_CHECK_RC_OK(hTest, rc);
236 if (RT_SUCCESS(rc))
237 {
238 g_drvTstMouse.pDrv->pfnPutEvent(g_drvTstMouse.pDrv, 123, -16, 1, -1, 3);
239 Urb.EndPt = 0x01;
240 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
241 }
242 if (RT_SUCCESS(rc))
243 {
244 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
245 if (pUrb)
246 {
247 if (pUrb == &Urb)
248 {
249 if ( Urb.abData[0] != 3 /* Buttons */
250 || Urb.abData[1] != 123 /* x */
251 || Urb.abData[2] != 240 /* 256 - y */
252 || Urb.abData[3] != 255 /* z */)
253 rc = VERR_GENERAL_FAILURE;
254 }
255 else
256 rc = VERR_GENERAL_FAILURE;
257 }
258 else
259 rc = VERR_GENERAL_FAILURE;
260 }
261 RTTEST_CHECK_RC_OK(hTest, rc);
262 tstMouseDestruct(hTest, pUsbIns);
263}
264
265
266static void testSendPositionAbs(RTTEST hTest)
267{
268 PPDMUSBINS pUsbIns = NULL;
269 VUSBURB Urb;
270 RTTestSub(hTest, "sending an absolute position event");
271 int rc = tstMouseConstruct(hTest, 0, "absolute", 1, &pUsbIns);
272 RT_ZERO(Urb);
273 if (RT_SUCCESS(rc))
274 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
275 if (RT_SUCCESS(rc))
276 {
277 if (g_drvTstMouse.pDrv)
278 g_drvTstMouse.pDrv->pfnPutEventAbs(g_drvTstMouse.pDrv, 300, 200, 1, 3, 3);
279 else
280 rc = VERR_PDM_MISSING_INTERFACE;
281 }
282 if (RT_SUCCESS(rc))
283 {
284 Urb.EndPt = 0x01;
285 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
286 }
287 if (RT_SUCCESS(rc))
288 {
289 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
290 if (pUrb)
291 {
292 if (pUrb == &Urb)
293 {
294 if ( Urb.abData[0] != 3 /* Buttons */
295 || (int8_t)Urb.abData[1] != -1 /* dz */
296 || (int8_t)Urb.abData[2] != -3 /* dw */
297 || *(uint16_t *)&Urb.abData[4] != 150 /* x >> 1 */
298 || *(uint16_t *)&Urb.abData[6] != 100 /* y >> 1 */)
299 rc = VERR_GENERAL_FAILURE;
300 }
301 else
302 rc = VERR_GENERAL_FAILURE;
303 }
304 else
305 rc = VERR_GENERAL_FAILURE;
306 }
307 RTTEST_CHECK_RC_OK(hTest, rc);
308 tstMouseDestruct(hTest, pUsbIns);
309}
310
311#if 0
312/** @todo PDM interface was updated. This is not working anymore. */
313static void testSendPositionMT(RTTEST hTest)
314{
315 PPDMUSBINS pUsbIns = NULL;
316 VUSBURB Urb;
317 RTTestSub(hTest, "sending a multi-touch position event");
318 int rc = tstMouseConstruct(hTest, 0, "multitouch", 1, &pUsbIns);
319 RT_ZERO(Urb);
320 if (RT_SUCCESS(rc))
321 {
322 rc = g_UsbHidMou.pfnUsbReset(pUsbIns, false);
323 }
324 if (RT_SUCCESS(rc))
325 {
326 if (g_drvTstMouse.pDrv)
327 g_drvTstMouse.pDrv->pfnPutEventMT(g_drvTstMouse.pDrv, 300, 200, 2,
328 3);
329 else
330 rc = VERR_PDM_MISSING_INTERFACE;
331 }
332 if (RT_SUCCESS(rc))
333 {
334 Urb.EndPt = 0x01;
335 rc = g_UsbHidMou.pfnUrbQueue(pUsbIns, &Urb);
336 }
337 if (RT_SUCCESS(rc))
338 {
339 PVUSBURB pUrb = g_UsbHidMou.pfnUrbReap(pUsbIns, 0);
340 if (pUrb)
341 {
342 if (pUrb == &Urb)
343 {
344 if ( Urb.abData[0] != 1 /* Report ID */
345 || Urb.abData[1] != 3 /* Contact flags */
346 || *(uint16_t *)&Urb.abData[2] != 150 /* x >> 1 */
347 || *(uint16_t *)&Urb.abData[4] != 100 /* y >> 1 */
348 || Urb.abData[6] != 2 /* Contact number */)
349 rc = VERR_GENERAL_FAILURE;
350 }
351 else
352 rc = VERR_GENERAL_FAILURE;
353 }
354 else
355 rc = VERR_GENERAL_FAILURE;
356 }
357 RTTEST_CHECK_RC_OK(hTest, rc);
358 tstMouseDestruct(hTest, pUsbIns);
359}
360#endif
361
362int main()
363{
364 /*
365 * Init the runtime, test and say hello.
366 */
367 RTTEST hTest;
368 int rc = RTTestInitAndCreate("tstUsbMouse", &hTest);
369 if (rc)
370 return rc;
371 RTTestBanner(hTest);
372 /* Set up our faked PDMUSBHLP interface. */
373 g_tstUsbHlp.u32Version = PDM_USBHLP_VERSION;
374 g_tstUsbHlp.pfnVMSetErrorV = tstVMSetErrorV;
375 g_tstUsbHlp.pfnDriverAttach = tstDriverAttach;
376 g_tstUsbHlp.u32TheEnd = PDM_USBHLP_VERSION;
377 /* Set up our global mouse driver */
378 g_drvTstMouse.IBase.pfnQueryInterface = tstMouseQueryInterface;
379 g_drvTstMouse.IConnector.pfnReportModes = tstMouseReportModes;
380
381 /*
382 * Run the tests.
383 */
384 testConstructAndDestruct(hTest);
385 testSendPositionRel(hTest);
386 testSendPositionAbs(hTest);
387 /* testSendPositionMT(hTest); */
388 return RTTestSummaryAndDestroy(hTest);
389}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette