diff options
Diffstat (limited to 'src/VBox/Main/testcase/tstMouseImpl.cpp')
-rw-r--r-- | src/VBox/Main/testcase/tstMouseImpl.cpp | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/src/VBox/Main/testcase/tstMouseImpl.cpp b/src/VBox/Main/testcase/tstMouseImpl.cpp new file mode 100644 index 00000000..361daf14 --- /dev/null +++ b/src/VBox/Main/testcase/tstMouseImpl.cpp @@ -0,0 +1,459 @@ +/* $Id: tstMouseImpl.cpp $ */ +/** @file + * Main unit test - Mouse class. + */ + +/* + * Copyright (C) 2011-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/****************************************************************************** +* Header Files * +******************************************************************************/ +#define IN_VMM_R3 /* Kill most Windows warnings on CFGMR3* implementations. */ +#include "MouseImpl.h" +#include "VMMDev.h" +#include "DisplayImpl.h" + +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/pdmdrv.h> +#include <VBox/VMMDev.h> +#include <iprt/assert.h> +#include <iprt/test.h> + +#ifndef RT_OS_WINDOWS +NS_DECL_CLASSINFO(Mouse) +NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Mouse, IMouse) +#endif + +PDMIVMMDEVPORT VMMDevPort; + +class TestVMMDev : public VMMDevMouseInterface +{ + PPDMIVMMDEVPORT getVMMDevPort(void) { return &VMMDevPort; } +}; + +class TestDisplay : public DisplayMouseInterface +{ + void getFramebufferDimensions(int32_t *px1, int32_t *py1, + int32_t *px2, int32_t *py2); + int getScreenResolution(uint32_t cScreen, ULONG *pcx, ULONG *pcy, + ULONG *pcBPP, LONG *pXOrigin, LONG *pYOrigin); +}; + +class TestConsole : public ConsoleMouseInterface +{ +public: + VMMDevMouseInterface *getVMMDevMouseInterface() { return &mVMMDev; } + DisplayMouseInterface *getDisplayMouseInterface() { return &mDisplay; } + /** @todo why on earth is this not implemented? */ + void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, + BOOL supportsMT, BOOL needsHostCursor) {} + +private: + TestVMMDev mVMMDev; + TestDisplay mDisplay; +}; + +static int pdmdrvhlpAttach(PPDMDRVINS pDrvIns, uint32_t fFlags, + PPDMIBASE *ppBaseInterface) +{ + return VERR_PDM_NO_ATTACHED_DRIVER; +} + +static struct PDMDRVHLPR3 pdmHlpR3 = +{ + PDM_DRVHLPR3_VERSION, + pdmdrvhlpAttach, + NULL, /* pfnDetach */ + NULL, /* pfnDetachSelf */ + NULL, /* pfnMountPrepare */ + NULL, /* pfnAssertEMT */ + NULL, /* pfnAssertOther */ + NULL, /* pfnVMSetError */ + NULL, /* pfnVMSetErrorV */ + NULL, /* pfnVMSetRuntimeError */ + NULL, /* pfnVMSetRuntimeErrorV */ + NULL, /* pfnVMState */ + NULL, /* pfnVMTeleportedAndNotFullyResumedYet */ + NULL, /* pfnGetSupDrvSession */ + NULL, /* pfnQueueCreate */ + NULL, /* pfnTMGetVirtualFreq */ + NULL, /* pfnTMGetVirtualTime */ + NULL, /* pfnTMTimerCreate */ + NULL, /* pfnSSMRegister */ + NULL, /* pfnSSMDeregister */ + NULL, /* pfnDBGFInfoRegister */ + NULL, /* pfnDBGFInfoDeregister */ + NULL, /* pfnSTAMRegister */ + NULL, /* pfnSTAMRegisterF */ + NULL, /* pfnSTAMRegisterV */ + NULL, /* pfnSTAMDeregister */ + NULL, /* pfnSUPCallVMMR0Ex */ + NULL, /* pfnUSBRegisterHub */ + NULL, /* pfnSetAsyncNotification */ + NULL, /* pfnAsyncNotificationCompleted */ + NULL, /* pfnThreadCreate */ + NULL, /* pfnAsyncCompletionTemplateCreate */ +#ifdef VBOX_WITH_NETSHAPER + NULL, /* pfnNetShaperAttach */ + NULL, /* pfnNetShaperDetach */ +#endif + NULL, /* pfnLdrGetRCInterfaceSymbols */ + NULL, /* pfnLdrGetR0InterfaceSymbols */ + NULL, /* pfnCritSectInit */ + NULL, /* pfnCallR0 */ + NULL, /* pfnFTSetCheckpoint */ + NULL, /* pfnBlkCacheRetain */ + NULL, /* pfnVMGetSuspendReason */ + NULL, /* pfnVMGetResumeReason */ + NULL, /* pfnReserved0 */ + NULL, /* pfnReserved1 */ + NULL, /* pfnReserved2 */ + NULL, /* pfnReserved3 */ + NULL, /* pfnReserved4 */ + NULL, /* pfnReserved5 */ + NULL, /* pfnReserved6 */ + NULL, /* pfnReserved7 */ + NULL, /* pfnReserved8 */ + NULL, /* pfnReserved9 */ + PDM_DRVHLPR3_VERSION /* u32TheEnd */ +}; + +static struct +{ + int32_t dx; + int32_t dy; + int32_t dz; + int32_t dw; +} mouseEvent; + +static int mousePutEvent(PPDMIMOUSEPORT pInterface, int32_t iDeltaX, + int32_t iDeltaY, int32_t iDeltaZ, int32_t iDeltaW, + uint32_t fButtonStates) +{ + mouseEvent.dx = iDeltaX; + mouseEvent.dy = iDeltaY; + mouseEvent.dz = iDeltaZ; + mouseEvent.dw = iDeltaW; + return VINF_SUCCESS; +} + +static struct +{ + uint32_t cx; + uint32_t cy; + int32_t dz; + int32_t dw; + uint32_t fButtonStates; +} mouseEventAbs; + +static int mousePutEventAbs(PPDMIMOUSEPORT pInterface, uint32_t uX, + uint32_t uY, int32_t iDeltaZ, int32_t iDeltaW, + uint32_t fButtonStates) +{ + mouseEventAbs.cx = uX; + mouseEventAbs.cy = uY; + mouseEventAbs.dz = iDeltaZ; + mouseEventAbs.dw = iDeltaW; + mouseEventAbs.fButtonStates = fButtonStates; + return VINF_SUCCESS; +} + +static struct PDMIMOUSEPORT pdmiMousePort = +{ + mousePutEvent, + mousePutEventAbs, + NULL /* pfnPutEventMT */ +}; + +static void *pdmiBaseQuery(struct PDMIBASE *pInterface, const char *pszIID) +{ + return &pdmiMousePort; +} + +static struct PDMIBASE pdmiBase = +{ + pdmiBaseQuery +}; + +static struct PDMDRVINS pdmdrvInsCore = +{ + PDM_DRVINS_VERSION, + 0, /* iInstance */ + NIL_RTRCPTR, /* pHlpRC */ + NIL_RTRCPTR, /* pvInstanceDataRC */ + NIL_RTR0PTR, /* pHelpR0 */ + NIL_RTR0PTR, /* pvInstanceDataR0 */ + &pdmHlpR3, + NULL, /* pvInstanceDataR3 */ + NIL_RTR3PTR, /* pReg */ + NIL_RTR3PTR, /* pCfg */ + &pdmiBase, + NULL, /* pDownBase */ + { /* IBase */ + NULL /* pfnQueryInterface */ + }, + 0, /* fTracing */ + 0, /* idTracing */ +#if HC_ARCH_BITS == 32 + { 0 }, /* au32Padding */ +#endif + { + { 0 } /* padding */ + }, /* Internal */ + { 0 } /* achInstanceData */ +}; + +static struct PDMDRVINS *ppdmdrvIns = NULL; + +ComObjPtr<Mouse> pMouse; +ConsoleMouseInterface *pConsole = NULL; + +static struct +{ + int32_t x; + int32_t y; +} absoluteMouse; + +static int setAbsoluteMouse(PPDMIVMMDEVPORT, int32_t x, int32_t y) +{ + absoluteMouse.x = x; + absoluteMouse.y = y; + return VINF_SUCCESS; +} + +static int updateMouseCapabilities(PPDMIVMMDEVPORT, uint32_t, uint32_t) +{ + return VINF_SUCCESS; +} + +void TestDisplay::getFramebufferDimensions(int32_t *px1, int32_t *py1, + int32_t *px2, int32_t *py2) +{ + if (px1) + *px1 = -320; + if (py1) + *py1 = -240; + if (px2) + *px2 = 320; + if (py2) + *py2 = 240; +} + +int TestDisplay::getScreenResolution(uint32_t cScreen, ULONG *pcx, + ULONG *pcy, ULONG *pcBPP, LONG *pXOrigin, LONG *pYOrigin) +{ + NOREF(cScreen); + if (pcx) + *pcx = 640; + if (pcy) + *pcy = 480; + if (pcBPP) + *pcBPP = 32; + if (pXOrigin) + *pXOrigin = 0; + if (pYOrigin) + *pYOrigin = 0; + return S_OK; +} + +/****************************************************************************** +* Main test code * +******************************************************************************/ + +static int setup(void) +{ + PCFGMNODE pCfg = NULL; + Mouse *pMouse2; + int rc = VERR_NO_MEMORY; + VMMDevPort.pfnSetAbsoluteMouse = setAbsoluteMouse; + VMMDevPort.pfnUpdateMouseCapabilities = updateMouseCapabilities; + HRESULT hrc = pMouse.createObject(); + AssertComRC(hrc); + if (FAILED(hrc)) + return VERR_GENERAL_FAILURE; + pConsole = new TestConsole; + pMouse->init(pConsole); + ppdmdrvIns = (struct PDMDRVINS *) RTMemAllocZ( sizeof(struct PDMDRVINS) + + Mouse::DrvReg.cbInstance); + *ppdmdrvIns = pdmdrvInsCore; + pMouse2 = pMouse; + pCfg = CFGMR3CreateTree(NULL); + if (pCfg) + { + rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pMouse2); + if (RT_SUCCESS(rc)) + Mouse::DrvReg.pfnConstruct(ppdmdrvIns, pCfg, 0); + } + return rc; +} + +static void teardown(void) +{ + pMouse.setNull(); + if (pConsole) + delete pConsole; + if (ppdmdrvIns) + RTMemFree(ppdmdrvIns); +} + +static bool approxEq(int a, int b, int prec) +{ + return a - b < prec && b - a < prec; +} + +/** @test testAbsToVMMDevNewProtocol */ +static void testAbsToVMMDevNewProtocol(RTTEST hTest) +{ + PPDMIBASE pBase; + PPDMIMOUSECONNECTOR pConnector; + + RTTestSub(hTest, "Absolute event to VMMDev, new protocol"); + pBase = &ppdmdrvIns->IBase; + pConnector = (PPDMIMOUSECONNECTOR)pBase->pfnQueryInterface(pBase, + PDMIMOUSECONNECTOR_IID); + pConnector->pfnReportModes(pConnector, true, false, false); + pMouse->onVMMDevGuestCapsChange( VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE + | VMMDEV_MOUSE_NEW_PROTOCOL); + pMouse->PutMouseEventAbsolute(0, 0, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0x8000, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0x8000, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(-319, -239, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(320, 240, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0xffff, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0xffff, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + RTTestSubDone(hTest); +} + +/** @test testAbsToVMMDevOldProtocol */ +static void testAbsToVMMDevOldProtocol(RTTEST hTest) +{ + PPDMIBASE pBase; + PPDMIMOUSECONNECTOR pConnector; + + RTTestSub(hTest, "Absolute event to VMMDev, old protocol"); + pBase = &ppdmdrvIns->IBase; + pConnector = (PPDMIMOUSECONNECTOR)pBase->pfnQueryInterface(pBase, + PDMIMOUSECONNECTOR_IID); + pConnector->pfnReportModes(pConnector, true, false, false); + pMouse->onVMMDevGuestCapsChange(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE); + pMouse->PutMouseEventAbsolute(320, 240, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0x8000, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0x8000, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(0, 0, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(-319, -239, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, -0x8000, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, -0x8000, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + RTTestSubDone(hTest); +} + +/** @test testAbsToAbsDev */ +static void testAbsToAbsDev(RTTEST hTest) +{ + PPDMIBASE pBase; + PPDMIMOUSECONNECTOR pConnector; + + RTTestSub(hTest, "Absolute event to absolute device"); + pBase = &ppdmdrvIns->IBase; + pConnector = (PPDMIMOUSECONNECTOR)pBase->pfnQueryInterface(pBase, + PDMIMOUSECONNECTOR_IID); + pConnector->pfnReportModes(pConnector, false, true, false); + pMouse->onVMMDevGuestCapsChange(VMMDEV_MOUSE_NEW_PROTOCOL); + pMouse->PutMouseEventAbsolute(0, 0, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cx, 0x8000, 200), + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cy, 0x8000, 200), + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + pMouse->PutMouseEventAbsolute(-319, -239, 0, 0, 3); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cx, 0, 200), + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cy, 0, 200), + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + RTTESTI_CHECK_MSG(mouseEventAbs.fButtonStates == 3, + ("mouseEventAbs.fButtonStates=%u\n", + (unsigned) mouseEventAbs.fButtonStates)); + pMouse->PutMouseEventAbsolute(320, 240, -3, 2, 1); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cx, 0xffff, 200), + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cy, 0xffff, 200), + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + RTTESTI_CHECK_MSG(mouseEventAbs.fButtonStates == 1, + ("mouseEventAbs.fButtonStates=%u\n", + (unsigned) mouseEventAbs.fButtonStates)); + RTTESTI_CHECK_MSG(mouseEventAbs.dz == -3, + ("mouseEventAbs.dz=%d\n", (int) mouseEvent.dz)); + RTTESTI_CHECK_MSG(mouseEventAbs.dw == 2, + ("mouseEventAbs.dw=%d\n", (int) mouseEvent.dw)); + mouseEventAbs.cx = mouseEventAbs.cy = 0xffff; + pMouse->PutMouseEventAbsolute(-640, -480, 0, 0, 0); + RTTESTI_CHECK_MSG(mouseEventAbs.cx == 0xffff, + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(mouseEventAbs.cy == 0xffff, + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + RTTestSubDone(hTest); +} + +/** @todo generate this using the @test blocks above */ +typedef void (*PFNTEST)(RTTEST); +static PFNTEST g_tests[] = +{ + testAbsToVMMDevNewProtocol, + testAbsToVMMDevOldProtocol, + testAbsToAbsDev, + NULL +}; + +int main(void) +{ + /* + * Init the runtime, test and say hello. + */ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstMouseImpl", &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + /* + * Run the tests. + */ + for (unsigned i = 0; g_tests[i]; ++i) + { + int rc = setup(); + AssertRC(rc); + if (RT_SUCCESS(rc)) + g_tests[i](hTest); + teardown(); + } + + /* + * Summary + */ + return RTTestSummaryAndDestroy(hTest); +} + |