VirtualBox

Ignore:
Timestamp:
Apr 20, 2009 1:52:58 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
46136
Message:

GuestHost/SharedClipboard: add testcases for the X11 clipboard code and fix some issues they revealed

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp

    r18890 r19027  
    412412        = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData);
    413413    VBOXCLIPBOARDCONTEXTX11 *pCtx = pRequest->pCtx;
     414    pRequest->rc = VINF_SUCCESS;
    414415    LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData,
    415416                 *pcLen, *piFormat));
     
    418419    unsigned cTextLen = (*pcLen) * (*piFormat) / 8;
    419420    /* The X Toolkit may have failed to get the clipboard selection for us. */
    420     if (*atomType == XT_CONVERT_FAIL)
     421    if (*atomType == XT_CONVERT_FAIL) /* timeout */
     422    {
     423        pRequest->rc = VERR_TIMEOUT;
     424        RTSemEventSignal(pCtx->waitForData);
    421425        return;
     426    }
    422427    /* The clipboard selection may have changed before we could get it. */
    423428    if (NULL == pValue)
     429    {
     430        pRequest->rc = VERR_NO_DATA;
     431        RTSemEventSignal(pCtx->waitForData);
    424432        return;
     433    }
    425434    /* In which format is the clipboard data? */
    426435    switch (pCtx->X11TextFormat)
     
    454463        LogFunc (("bad target format\n"));
    455464        XtFree(reinterpret_cast<char *>(pValue));
     465        pRequest->rc = VERR_INVALID_PARAMETER;
     466        RTSemEventSignal(pCtx->waitForData);
    456467        return;
    457468    }
     
    482493
    483494    Log3 (("%s: called\n", __PRETTY_FUNCTION__));
    484     if (*atomType == XT_CONVERT_FAIL)
     495    if (*atomType == XT_CONVERT_FAIL) /* timeout */
    485496    {
    486497        LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n"));
     498        pCtx->atomX11TextFormat = None;
     499        pCtx->X11TextFormat = INVALID;
    487500        return;
    488501    }
     
    564577    Log3 (("%s: called\n", __PRETTY_FUNCTION__));
    565578    /* Get the current clipboard contents */
    566     if (pCtx->eOwner == X11)
     579    if ((pCtx->eOwner != VB))
    567580    {
    568581        Log3 (("%s: requesting the targets that the host clipboard offers\n",
     
    817830            /** @todo Check whether the guest gets a format announcement at
    818831              *       startup. */
    819             pCtx->eOwner = VB;
     832            pCtx->eOwner = NONE;
    820833            VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 0);
    821834        }
     
    859872    /* This might mean that we are getting stopped twice. */
    860873    AssertReturn(pCtx->widget != NULL, VERR_WRONG_ORDER);
    861     pCtx->eOwner = NONE;
    862     pCtx->X11TextFormat = INVALID;
    863     pCtx->X11BitmapFormat = INVALID;
    864874    LogRelFunc(("stopping the shared clipboard X11 backend\n"));
    865875
     
    874884    XSendEvent(XtDisplay(pCtx->widget), XtWindow(pCtx->widget), false, 0, &ev);
    875885    XFlush(XtDisplay(pCtx->widget));
     886    pCtx->eOwner = NONE;
     887    pCtx->X11TextFormat = INVALID;
     888    pCtx->X11BitmapFormat = INVALID;
    876889    do
    877890    {
     
    984997    PRTUTF16 pu16SrcText, pu16DestText;
    985998    char *pu8DestText;
    986     void *pvVBox;
    987     uint32_t cbVBox;
     999    void *pvVBox = NULL;
     1000    uint32_t cbVBox = 0;
    9881001    size_t cwSrcLen, cwDestLen, cbDestLen;
    9891002    int rc;
     
    10911104{
    10921105    PRTUTF16 pu16SrcText, pu16DestText;
    1093     void *pvVBox;
    1094     uint32_t cbVBox;
     1106    void *pvVBox = NULL;
     1107    uint32_t cbVBox = 0;
    10951108    char *pu8DestText = 0;
    10961109    size_t cwSrcLen, cwDestLen, cbDestLen;
     
    12931306
    12941307    LogFlowFunc (("u32Formats=%d\n", u32Formats));
    1295     if ((pCtx->eOwner == VB) && (pCtx->vboxFormats == u32Formats))
    1296     {
    1297         /* We already own the clipboard, so no need to grab it, especially as
    1298          * that can lead to races due to the asynchronous nature of the X11
    1299          * clipboard.  This event may also have been sent out by the guest to
    1300          * invalidate the Windows clipboard cache, required because X11 can't
    1301          * always tell if the clipboard content has changed. */
    1302         /** @note what races? */
    1303         /** @note if pCtx->vboxFormats == 0, we may not have really grabbed
    1304          * the clipboard. */
    1305         /** @todo clean up the last, it is liable to cause problems. */
    1306         LogFlowFunc(("returning\n"));
    1307         return;
    1308     }
    13091308    pCtx->vboxFormats = u32Formats;
    13101309    if (u32Formats == 0)
    13111310    {
    13121311        /* This is just an automatism, not a genuine anouncement */
     1312        XtDisownSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime);
     1313        pCtx->eOwner = NONE;
    13131314        LogFlowFunc(("returning\n"));
    13141315        return;
     
    13551356        /* no data available */
    13561357        *pRequest->pcbActual = 0;
     1358        pRequest->rc = VINF_SUCCESS;
    13571359        return VINF_SUCCESS;
    13581360    }
    13591361
    13601362    LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb));
     1363    pRequest->rc = VERR_WRONG_ORDER;
    13611364
    13621365    /*
    1363      * The guest wants to read data in the given format.
     1366     * VBox wants to read data in the given format.
    13641367     */
    1365     if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     1368    if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
    13661369    {
    13671370        if (pCtx->X11TextFormat == INVALID)
     
    13691372            /* No data available. */
    13701373            *pRequest->pcbActual = 0;
    1371             return VERR_NO_DATA;  /* The guest thinks we have data and we don't */
     1374            return VERR_NO_DATA;  /* VBox thinks we have data and we don't */
    13721375        }
    13731376        /* Initially set the size of the data read to zero in case we fail
     
    13801383                            reinterpret_cast<XtPointer>(pRequest),
    13811384                            CurrentTime);
    1382         /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called.  The
    1383            callback will signal the event semaphore when it has processed the data for us. */
     1385        /* When the data arrives, the vboxClipboardGetDataFromX11 callback
     1386        * will be called.  The callback will signal the event semaphore when
     1387        * it has processed the data for us. */
    13841388
    13851389        int rc = RTSemEventWait(pCtx->waitForData, RT_INDEFINITE_WAIT);
     
    13911395        return VERR_NOT_IMPLEMENTED;
    13921396    }
    1393     return VINF_SUCCESS;
     1397    LogFlowFunc(("returning %Rrc\n", pRequest->rc));
     1398    return pRequest->rc;
    13941399}
    13951400
     
    13991404#include <iprt/stream.h>
    14001405
     1406enum { MAX_ATTEMPTS = 10 };
     1407
    14011408static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestX11;
    14021409static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestVBox;
    1403 static const char g_au16Text[] = "H\0e\0l\0l\0o\0 \0w\0o\0r\0l\0d\0\r\0\n\0\0";
     1410
     1411/** Quick Utf16 string class, initialised from a Utf8 string */
     1412class testUtf16String
     1413{
     1414    /** Stores the Utf16 data.  NULL if something went wrong. */
     1415    PRTUTF16 mData;
     1416    /** Stores the size in bytes of the data.  0 if something went wrong. */
     1417    size_t mSize;
     1418public:
     1419    /** Constructor
     1420     * @param aString the Utf8 representation of the string data
     1421     */
     1422    testUtf16String(const char *aString)
     1423    {
     1424        int rc = RTStrToUtf16(aString, &mData);
     1425        if (RT_FAILURE(rc))
     1426        {
     1427            mData = NULL;
     1428            mSize = 0;
     1429            return;
     1430        }
     1431        mSize = RTUtf16Len(mData) * 2 + 2;
     1432    }
     1433    /** Destructor */
     1434    ~testUtf16String()
     1435    {
     1436        RTUtf16Free(mData);
     1437    }
     1438    /** Getter for the data */
     1439    PCRTUTF16 getData() { return mData; }
     1440    /** Getter for the data size */
     1441    size_t getSize() { return mSize; }
     1442};
     1443
     1444/** Parameters for a test run. */
     1445static struct testData
     1446{
     1447    /** The string data we are offering. */
     1448    testUtf16String data;
     1449    /** The size of the buffer to receive the request data */
     1450    uint32_t cchBuffer;
     1451    /** The format we request the data in */
     1452    PCRTUTF16 getData() { return data.getData(); }
     1453    /** Getter for the Utf16 string data size in bytes */
     1454    size_t getSize() { return data.getSize(); }
     1455    /** Is the test expected to produce a buffer overflow? */
     1456    bool overflow() { return cchBuffer < getSize(); }
     1457} g_sTestData[] =
     1458{
     1459    { "Hello world\r\n", 256 },
     1460    { "Goodbye world", 28 },
     1461    { "", 2 },
     1462    /* This should produce a buffer overflow */
     1463    { "Goodbye world", 27 },
     1464};
     1465
     1466/** Which line of the table above are we currently testing? */
     1467size_t g_testNum = 0;
     1468enum { MAX_TESTS = RT_ELEMENTS(g_sTestData) };
     1469/** Are we doing a timeout test?  Ugly, but whatever. */
     1470static bool g_testTimeout = false;
     1471
     1472/** @todo the current code can't test the following conditions:
     1473 *         * the X11 clipboard offers non-Utf8 text
     1474 *         * the X11 clipboard offers invalid Utf8 text
     1475 */
     1476/** @todo stress test our context store code?  Probably not important... */
    14041477
    14051478int VBoxX11ClipboardReadVBoxData(VBOXCLIPBOARDCONTEXT *pCtx,
     
    14081481{
    14091482    LogFlowFunc(("pCtx = %p\n", pCtx));
    1410     void *retval = RTMemDup(g_au16Text, sizeof(g_au16Text));
    1411     if (!retval)
    1412         return VERR_NO_MEMORY;
     1483    /* This should only ever be called for the second "test" clipboard. */
     1484    AssertReturn(pCtx == (VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11
     1485                         /* Magic cookie */, VERR_WRONG_ORDER);
     1486    /* Timeout test hack */
     1487    if (g_testTimeout)
     1488    {
     1489        RTThreadSleep(200);
     1490        /* Try to return data after we have been timed out. */
     1491        *ppv = RTMemDup((const void *) "Scribblings", sizeof("Scribblings"));
     1492        *pcb = sizeof("Scribblings");
     1493        LogFlowFunc(("sleep finished, returning\n"));
     1494        return VINF_SUCCESS;
     1495    }
     1496    /* Sanity. */
     1497    AssertReturn(g_testNum < MAX_TESTS, VERR_WRONG_ORDER);
     1498    testData *pData = &g_sTestData[g_testNum];
     1499    AssertPtrReturn(pData->getData(), VERR_NO_MEMORY);
     1500    AssertReturn(pData->getSize(), VERR_WRONG_ORDER);
     1501    void *retval = RTMemDup((const void *) pData->getData(),
     1502                            pData->getSize());
     1503    AssertPtrReturn(retval, VERR_NO_MEMORY);
    14131504    *ppv = (void *) retval;
    1414     *pcb = sizeof(g_au16Text);
     1505    *pcb = pData->getSize();
     1506    LogFlowFunc(("returning\n"));
    14151507    return VINF_SUCCESS;
    14161508}
     
    14271519}
    14281520
     1521/** Initial tests that can be done while the clipboard contents are still
     1522 * invalid.
     1523 * @returns boolean success value
     1524 * @note    prints status information to stdout
     1525 */
     1526bool testInvalid(void)
     1527{
     1528    bool fSuccess = true;
     1529    char pc[256];
     1530    uint32_t cbActual;
     1531    VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc),
     1532                                    &cbActual, VINF_SUCCESS, g_pCtxTestX11};
     1533    RTPrintf("tstClipboardX11:  TESTING a request for an invalid data format\n");
     1534    int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
     1535                                         0xffff, &request);
     1536    RTPrintf("Returned %Rrc - %s\n", rc,
     1537             rc == VERR_NOT_IMPLEMENTED ? "SUCCESS" : "FAILURE");
     1538    if (rc != VERR_NOT_IMPLEMENTED)
     1539        fSuccess = false;
     1540    RTPrintf("tstClipboardX11:  TESTING a request for data from an empty clipboard\n");
     1541    rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
     1542                         VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request);
     1543    RTPrintf("Returned %Rrc - %s\n", rc,
     1544             rc == VERR_NO_DATA ? "SUCCESS" : "FAILURE");
     1545    if (rc != VERR_NO_DATA)
     1546        fSuccess = false;
     1547    return fSuccess;
     1548}
     1549
     1550/** Tests an entry in the table above.
     1551 * @returns boolean success value
     1552 * @note    prints status information to stdout
     1553 */
     1554bool testEntry(testData *pData)
     1555{
     1556    bool fSuccess = false;
     1557    char pc[256];
     1558    uint32_t cbActual;
     1559    VBOXCLIPBOARDREQUEST request = {(void *) pc, pData->cchBuffer,
     1560                                    &cbActual, VINF_SUCCESS, g_pCtxTestX11};
     1561    for (int i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i)
     1562    {
     1563        int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
     1564                        VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request);
     1565        AssertReturn(RT_SUCCESS(rc), 1);
     1566        /* Did we expect and get an overflow? */
     1567        if (   RT_SUCCESS(rc)
     1568            && (cbActual == pData->getSize())
     1569            && pData->overflow())
     1570            fSuccess = true;
     1571        /* Did we expect a string and get it? */
     1572        else if (   RT_SUCCESS(rc)
     1573                 && (memcmp(pc, pData->getData(),
     1574                            pData->getSize()) == 0))
     1575            fSuccess = true;
     1576        else
     1577            RTThreadSleep(50);
     1578        if (fSuccess)
     1579            RTPrintf("text %ls, %sretval %Rrc - SUCCESS\n",
     1580                     pData->getData(),
     1581                     pData->overflow() ? "buffer overflow as expected, "
     1582                                       : "", rc);
     1583        else
     1584            RTPrintf("text %ls, retval %Rrc, attempt %d of %d\n",
     1585                     pData->getData(), rc, i + 1,
     1586                     MAX_ATTEMPTS);
     1587    }
     1588    if (!fSuccess)
     1589        RTPrintf("FAILURE.  Last string obtained was %.*lS\n",
     1590                 RT_MIN(cbActual / 2, 20), pc);
     1591    return fSuccess;
     1592}
     1593
    14291594int main()
    14301595{
    14311596    int rc = VINF_SUCCESS;
     1597    int status = 0;
     1598    /* We can't reasonably test anything without an X session, so just
     1599     * continue. */
     1600    if (!RTEnvGet("DISPLAY"))
     1601        return 0;
     1602    g_debugClipboard = true;
    14321603    RTR3Init();
    14331604    g_pCtxTestX11 = VBoxX11ClipboardConstructX11(NULL);
    14341605    g_pCtxTestVBox =
    14351606        VBoxX11ClipboardConstructX11((VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11);
    1436     rc = VBoxX11ClipboardStartX11(g_pCtxTestX11, true);
    14371607    rc = VBoxX11ClipboardStartX11(g_pCtxTestVBox, false);
    14381608    AssertRCReturn(rc, 1);
     1609    bool fSuccess = false;
     1610    /* Test a request for an invalid data format and data from an empty
     1611     * clipboard */
     1612    for (unsigned i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i)
     1613    {
     1614        rc = VBoxX11ClipboardStartX11(g_pCtxTestX11, false);
     1615        AssertRCReturn(rc, 1);
     1616        fSuccess = testInvalid();
     1617        VBoxX11ClipboardStopX11(g_pCtxTestX11);
     1618        if (!fSuccess)
     1619        {
     1620            RTPrintf("attempt %d of %d\n", i + 1, MAX_ATTEMPTS + 1);
     1621            RTThreadSleep(50);
     1622        }
     1623    }
     1624    if (!fSuccess)
     1625        status = 1;
     1626    rc = VBoxX11ClipboardStartX11(g_pCtxTestX11, true);
     1627    AssertRCReturn(rc, 1);
     1628    /* Claim the clipboard and make sure we get it */
    14391629    VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox,
    14401630                    VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
    1441     for (unsigned i = 0; i < 255 && g_pCtxTestX11->X11TextFormat == INVALID;
     1631    for (unsigned i = 0;
     1632            i < 255
     1633         && g_pCtxTestX11->X11TextFormat == INVALID;
    14421634         ++i)
    14431635        RTThreadSleep(50);
    14441636    AssertReturn(g_pCtxTestX11->X11TextFormat != INVALID, 1);
    1445     char pc[256];
    1446     uint32_t cbActual;
    1447     VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc), &cbActual,
    1448                                     g_pCtxTestX11};
     1637    /* Do general purpose clipboard tests */
    14491638    for (int i = 0; i < 2; ++i)
    14501639    {
    1451         enum { MAX_ATTEMPTS = 10 };
    1452         bool fSuccess = false;
    14531640        g_testUtf8 = (i == 0);
    14541641        g_testCText = (i == 1);
    1455         for (int j = 0; (j < MAX_ATTEMPTS) && !fSuccess; ++j)
    1456         {
    1457             RTPrintf("tstClipboardX11: TESTING sending and receiving of %s, attempt %d of %d\n",
    1458                      i == 0 ? "Utf-8" : "COMPOUND TEXT", j + 1, MAX_ATTEMPTS);
    1459             rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
    1460                             VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request);
    1461             AssertRCReturn(rc, 1);
    1462             if (memcmp(pc, g_au16Text, sizeof(g_au16Text)) == 0)
    1463                 fSuccess = true;
    1464             else
    1465                 RTThreadSleep(50);
    1466         }
    1467         if (fSuccess)
     1642        RTPrintf("tstClipboardX11: TESTING sending and receiving of %s\n",
     1643                 i == 0 ? "Utf-8" : "COMPOUND TEXT");
     1644        for (g_testNum = 0; g_testNum < MAX_TESTS; ++g_testNum)
     1645        {
     1646            if (!testEntry(&g_sTestData[g_testNum]))
     1647                status = 1;
     1648        }
     1649    }
     1650    /* Finally test timeouts. */
     1651    XtAppSetSelectionTimeout(g_pCtxTestX11->appContext, 10);
     1652    RTPrintf("tstClipboardX11: TESTING the clipboard timeout\n");
     1653    rc = VINF_SUCCESS;
     1654    g_testTimeout = true;
     1655    for (unsigned i = 0; (i < MAX_ATTEMPTS) && (rc != VERR_TIMEOUT); ++i)
     1656    {
     1657        char pc[256];
     1658        uint32_t cbActual;
     1659        VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc),
     1660                                        &cbActual, VINF_SUCCESS,
     1661                                        g_pCtxTestX11};
     1662        rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
     1663                    VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request);
     1664        AssertMsg(   RT_SUCCESS(rc)
     1665                  || (rc == VERR_TIMEOUT)
     1666                  || (rc == VERR_NO_DATA),
     1667                  ("rc = %Rrc\n", rc));
     1668        if (rc == VERR_TIMEOUT)
    14681669            RTPrintf("SUCCESS\n");
    14691670        else
    1470             RTPrintf("FAILURE.  Last string obtained was %.*lS\n",
    1471                      RT_MIN(cbActual / 2, 20), pc);
    1472     }
     1671        {
     1672            RTPrintf("Attempt %d of %d\n", i + 1, MAX_ATTEMPTS);
     1673            RTThreadSleep(50);
     1674        }
     1675    }
     1676    if (rc != VERR_TIMEOUT)
     1677        status = 1;
    14731678    rc = VBoxX11ClipboardStopX11(g_pCtxTestX11);
    14741679    AssertRCReturn(rc, 1);
     
    14771682    VBoxX11ClipboardDestructX11(g_pCtxTestX11);
    14781683    VBoxX11ClipboardDestructX11(g_pCtxTestVBox);
    1479     return 0;
     1684    return status;
    14801685}
    14811686
Note: See TracChangeset for help on using the changeset viewer.

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