VirtualBox

Changeset 19505 in vbox


Ignore:
Timestamp:
May 7, 2009 8:04:03 PM (16 years ago)
Author:
vboxsync
Message:

GuestHost/SharedClipboard/x11: better testcases and a couple of fixes found while creating them

Location:
trunk/src/VBox/GuestHost/SharedClipboard
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/Makefile.kmk

    r18892 r19505  
    2929#
    3030  if1of ($(KBUILD_TARGET),freebsd linux netbsd openbsd solaris)
    31    PROGRAMS += tstClipboardX11
     31   PROGRAMS += tstClipboardX11 tstClipboardX11Smoke
    3232   tstClipboardX11_TEMPLATE = VBOXR3TSTEXE
    33 # The second define here is to ensure that the testcase will run fast, without
    34 # waiting for any thread synchronisation.
    3533   tstClipboardX11_DEFS     = VBOX_WITH_HGCM TESTCASE
    3634   tstClipboardX11_SOURCES  = x11-clipboard.cpp clipboard-helper.cpp
    37    tstClipboardX11_LIBPATH  = $(VBOX_LIBPATH_X11)
    38    tstClipboardX11_LIBS     = $(LIB_RUNTIME) X11 Xt
     35   tstClipboardX11_LIBS     = $(LIB_RUNTIME)
     36
     37   tstClipboardX11Smoke_TEMPLATE = VBOXR3TSTEXE
     38   tstClipboardX11Smoke_DEFS     = VBOX_WITH_HGCM SMOKETEST
     39   tstClipboardX11Smoke_SOURCES  = x11-clipboard.cpp clipboard-helper.cpp
     40   tstClipboardX11Smoke_LIBPATH  = $(VBOX_LIBPATH_X11)
     41   tstClipboardX11Smoke_LIBS     = $(LIB_RUNTIME) X11 Xt
    3942
    4043# Set this in LocalConfig.kmk if you are working on the X11 clipboard service
     
    4750        export VBOX_LOG_DEST=nofile; $(INSTARGET_tstClipboardX11) quiet
    4851        $(QUIET)$(APPEND) -t "$@" "done"
     52
     53     TESTING  += $(PATH_tstClipboardX11Smoke)/tstClipboardX11Smoke.run
     54     OTHERS += $(PATH_tstClipboardX11Smoke)/tstClipboardX11Smoke.run
     55$$(PATH_tstClipboardX11Smoke)/tstClipboardX11Smoke.run: \
     56                $$(INSTARGET_tstClipboardX11)
     57        export VBOX_LOG_DEST=nofile; $(INSTARGET_tstClipboardX11Smoke) quiet
     58        $(QUIET)$(APPEND) -t "$@" "done"
    4959    endif
    5060   endif
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp

    r18398 r19505  
    3232    LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
    3333    AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER);
     34    if (cwSrc == 0)
     35    {
     36        *pcwDest = 0;
     37        LogFlowFunc(("empty source string, returning\n"));
     38        return VINF_SUCCESS;
     39    }
    3440/** @todo convert the remainder of the Assert stuff to AssertLogRel. */
    3541    /* We only take little endian Utf16 */
     
    3844        LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
    3945        AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
    40     }
    41     if (cwSrc == 0)
    42     {
    43         *pcwDest = 0;
    44         LogFlowFunc(("empty source string, returning\n"));
    45         return VINF_SUCCESS;
    4646    }
    4747    cwDest = 0;
     
    7979        AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
    8080    }
     81    if (cwSrc == 0)
     82    {
     83        if (cwDest == 0)
     84        {
     85            LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
     86            return VERR_BUFFER_OVERFLOW;
     87        }
     88        pu16Dest[0] = 0;
     89        LogFlowFunc(("empty source string, returning\n"));
     90        return VINF_SUCCESS;
     91    }
    8192    /* We only take little endian Utf16 */
    8293    if (pwszSrc[0] == UTF16BEMARKER)
     
    8495        LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
    8596        AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
    86     }
    87     if (cwSrc == 0)
    88     {
    89         if (cwDest == 0)
    90         {
    91             LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
    92             return VERR_BUFFER_OVERFLOW;
    93         }
    94         pu16Dest[0] = 0;
    95         LogFlowFunc(("empty source string, returning\n"));
    96         return VINF_SUCCESS;
    9797    }
    9898    /* Don't copy the endian marker. */
     
    155155        AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER);
    156156    }
     157    if (cwSrc == 0)
     158    {
     159        LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
     160        *pcwDest = 0;
     161        return VINF_SUCCESS;
     162    }
    157163    /* We only take little endian Utf16 */
    158164    if (pwszSrc[0] == UTF16BEMARKER)
     
    160166        LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string.  Returning VERR_INVALID_PARAMETER.\n"));
    161167        AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
    162     }
    163     if (cwSrc == 0)
    164     {
    165         LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
    166         *pcwDest = 0;
    167         return VINF_SUCCESS;
    168168    }
    169169    /* Calculate the size of the destination text string. */
  • trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp

    r19220 r19505  
    283283    int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
    284284    if (RT_SUCCESS(rc))
    285         rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen,
     285        rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen + 1,
    286286                                       pv, cb, pcbActual);
    287287    XtFree(reinterpret_cast<char *>(pValue));
     
    360360        rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
    361361    if (RT_SUCCESS(rc))
    362         rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen,
     362        rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen + 1,
    363363                                       pv, cb, pcbActual);
    364364    if (ppu8SrcText != NULL)
     
    625625}
    626626
     627enum { TIMER_FREQ = 200 /* ms */ };
     628
     629static void vboxClipboardPollX11ForTargets(XtPointer pUserData,
     630                                           XtIntervalId * /* hTimerId */);
     631static void clipSchedulePoller(VBOXCLIPBOARDCONTEXTX11 *pCtx,
     632                               XtTimerCallbackProc proc);
     633
     634#ifndef TESTCASE
     635void clipSchedulePoller(VBOXCLIPBOARDCONTEXTX11 *pCtx,
     636                        XtTimerCallbackProc proc)
     637{
     638    XtAppAddTimeOut(pCtx->appContext, TIMER_FREQ, proc, pCtx);
     639}
     640#endif
     641
    627642/**
    628643 * This timer callback is called every 200ms to check the contents of the X11
     
    633648 *        available.
    634649 */
    635 static void vboxClipboardPollX11ForTargets(XtPointer pUserData,
    636                                            XtIntervalId * /* hTimerId */)
     650void vboxClipboardPollX11ForTargets(XtPointer pUserData,
     651                                    XtIntervalId * /* hTimerId */)
    637652{
    638653    VBOXCLIPBOARDCONTEXTX11 *pCtx =
     
    650665    }
    651666    /* Re-arm our timer */
    652     XtAppAddTimeOut(pCtx->appContext, 200 /* ms */,
    653                     vboxClipboardPollX11ForTargets, pCtx);
    654 }
    655 
     667    clipSchedulePoller(pCtx, vboxClipboardPollX11ForTargets);
     668}
     669
     670#ifndef TESTCASE
    656671/**
    657672 * The main loop of our clipboard reader.
     
    664679    VBOXCLIPBOARDCONTEXTX11 *pCtx =
    665680            reinterpret_cast<VBOXCLIPBOARDCONTEXTX11 *>(pvUser);
    666     /* Set up a timer to poll the host clipboard */
    667     XtAppAddTimeOut(pCtx->appContext, 200 /* ms */,
    668                     vboxClipboardPollX11ForTargets, pCtx);
    669 
    670681    while (XtAppGetExitFlag(pCtx->appContext) == FALSE)
    671682        XtAppProcessEvent(pCtx->appContext, XtIMAll);
     
    673684    return VINF_SUCCESS;
    674685}
     686#endif
    675687
    676688/** X11 specific uninitialisation for the shared clipboard.
     
    759771        XtSetMappedWhenManaged(pCtx->widget, false);
    760772        XtRealizeWidget(pCtx->widget);
     773        /* Set up a timer to poll the host clipboard */
     774        clipSchedulePoller(pCtx, vboxClipboardPollX11ForTargets);
    761775    }
    762776    /* Create the pipes */
     
    766780        pCtx->wakeupPipeRead = pipes[0];
    767781        pCtx->wakeupPipeWrite = pipes[1];
    768         XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead,
    769                       (XtPointer) XtInputReadMask, vboxClipboardStopWorker,
    770                       (XtPointer) pCtx);
     782        if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead,
     783                           (XtPointer) XtInputReadMask,
     784                           vboxClipboardStopWorker, (XtPointer) pCtx))
     785            rc = VERR_NO_MEMORY;  /* What failure means is not doc'ed. */
    771786    }
    772787    else
     
    857872
    858873    rc = vboxClipboardInitX11(pCtx);
     874#ifndef TESTCASE
    859875    if (RT_SUCCESS(rc))
    860876    {
     
    864880            LogRel(("Failed to initialise the shared clipboard X11 backend.\n"));
    865881    }
     882#endif
    866883    if (RT_SUCCESS(rc))
    867884    {
     
    11231140    *atomTypeReturn = clipGetAtom(pCtx->widget, "UTF8_STRING");
    11241141    *pValReturn = reinterpret_cast<XtPointer>(pu8DestText);
    1125     *pcLenReturn = cbDestLen;
     1142    *pcLenReturn = cbDestLen + 1;
    11261143    *piFormatReturn = 8;
    11271144    return true;
     
    12531270    *atomTypeReturn = property.encoding;
    12541271    *pValReturn = reinterpret_cast<XtPointer>(property.value);
    1255     *pcLenReturn = property.nitems;
     1272    *pcLenReturn = property.nitems + 1;
    12561273    *piFormatReturn = property.format;
    12571274    return true;
     
    13491366}
    13501367
     1368static void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc,
     1369                         XtPointer client_data);
     1370#ifndef TESTCASE
     1371void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc,
     1372                  XtPointer client_data)
     1373{
     1374    XtAppAddTimeOut(app_context, 0, proc, client_data);
     1375}
     1376#endif
     1377
    13511378/** Structure used to pass information about formats that VBox supports */
    13521379typedef struct _VBOXCLIPBOARDFORMATS
     
    14291456        pFormats->pCtx = pCtx;
    14301457        pFormats->formats = u32Formats;
    1431         XtAppAddTimeOut(pCtx->appContext, 0, vboxClipboardAnnounceWorker,
    1432                         (XtPointer) pFormats);
     1458        clipSchedule(pCtx->appContext, vboxClipboardAnnounceWorker,
     1459                     (XtPointer) pFormats);
    14331460    }
    14341461}
     
    15181545    {
    15191546        /* We use this to schedule a worker function on the event thread. */
    1520         XtAppAddTimeOut(pCtx->appContext, 0, vboxClipboardReadX11Worker,
    1521                         (XtPointer) &request);
     1547        clipSchedule(pCtx->appContext, vboxClipboardReadX11Worker,
     1548                     (XtPointer) &request);
    15221549        rc = RTSemEventWait(request.finished, RT_INDEFINITE_WAIT);
    15231550        if (RT_SUCCESS(rc))
     
    15321559#include <iprt/initterm.h>
    15331560#include <iprt/stream.h>
    1534 
    1535 enum { MAX_ATTEMPTS = 10 };
    1536 
    1537 static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestX11;
    1538 static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestVBox;
    1539 
    1540 /** Quick Utf16 string class, initialised from a Utf8 string */
    1541 class testUtf16String
    1542 {
    1543     /** Stores the Utf16 data.  NULL if something went wrong. */
    1544     PRTUTF16 mData;
    1545     /** Stores the size in bytes of the data.  0 if something went wrong. */
    1546     size_t mSize;
    1547 public:
    1548     /** Constructor
    1549      * @param aString the Utf8 representation of the string data
    1550      */
    1551     testUtf16String(const char *aString)
    1552     {
    1553         int rc = RTStrToUtf16(aString, &mData);
    1554         if (RT_FAILURE(rc))
    1555         {
    1556             mData = NULL;
    1557             mSize = 0;
    1558             return;
    1559         }
    1560         mSize = RTUtf16Len(mData) * 2 + 2;
    1561     }
    1562     /** Destructor */
    1563     ~testUtf16String()
    1564     {
    1565         RTUtf16Free(mData);
    1566     }
    1567     /** Getter for the data */
    1568     PCRTUTF16 getData() { return mData; }
    1569     /** Getter for the data size */
    1570     size_t getSize() { return mSize; }
    1571 };
    1572 
    1573 /** Parameters for a test run. */
    1574 static struct testData
    1575 {
    1576     /** The string data we are offering. */
    1577     testUtf16String data;
    1578     /** The size of the buffer to receive the request data */
    1579     uint32_t cchBuffer;
    1580     /** The format we request the data in */
    1581     PCRTUTF16 getData() { return data.getData(); }
    1582     /** Getter for the Utf16 string data size in bytes */
    1583     size_t getSize() { return data.getSize(); }
    1584     /** Is the test expected to produce a buffer overflow? */
    1585     bool overflow() { return cchBuffer < getSize(); }
    1586 } g_sTestData[] =
    1587 {
    1588     { "Hello world\r\n", 256 },
    1589     { "Goodbye world", 28 },
    1590     { "", 2 },
    1591     /* This should produce a buffer overflow */
    1592     { "Goodbye world", 27 },
    1593 };
    1594 
    1595 /** Which line of the table above are we currently testing? */
    1596 size_t g_testNum = 0;
    1597 enum { MAX_TESTS = RT_ELEMENTS(g_sTestData) };
    1598 /** Are we doing a timeout test?  Ugly, but whatever. */
    1599 static bool g_testTimeout = false;
    1600 
    1601 /** @todo the current code can't test the following conditions:
    1602  *         * the X11 clipboard offers non-Utf8 text
    1603  *         * the X11 clipboard offers invalid Utf8 text
    1604  */
    1605 /** @todo stress test our context store code?  Probably not important... */
    1606 
     1561#include <poll.h>
     1562
     1563#define TEST_NAME "tstClipboardX11"
     1564#define TEST_WIDGET (Widget)0xffff
     1565
     1566/* Our X11 clipboard target poller */
     1567static XtTimerCallbackProc g_pfnPoller = NULL;
     1568/* User data for the poller function. */
     1569static XtPointer g_pPollerData = NULL;
     1570
     1571/* For the testcase, we install the poller function in a global variable
     1572 * which is called when the testcase updates the X11 targets. */
     1573void clipSchedulePoller(VBOXCLIPBOARDCONTEXTX11 *pCtx,
     1574                        XtTimerCallbackProc proc)
     1575{
     1576    g_pfnPoller = proc;
     1577    g_pPollerData = (XtPointer)pCtx;
     1578}
     1579
     1580static bool clipPollTargets()
     1581{
     1582    if (!g_pfnPoller)
     1583        return false;
     1584    g_pfnPoller(g_pPollerData, NULL);
     1585    return true;
     1586}
     1587
     1588/* For the purpose of the test case, we just execute the procedure to be
     1589 * scheduled, as we are running single threaded. */
     1590void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc,
     1591                  XtPointer client_data)
     1592{
     1593    proc(client_data, NULL);
     1594}
     1595
     1596void XtFree(char *ptr)
     1597{ RTMemFree((void *) ptr); }
     1598
     1599/* The data in the simulated VBox clipboard */
     1600static int g_vboxDataRC = VINF_SUCCESS;
     1601static void *g_vboxDatapv = NULL;
     1602static uint32_t g_vboxDatacb = 0;
     1603
     1604/* Set empty data in the simulated VBox clipboard. */
     1605static void clipEmptyVBox(VBOXCLIPBOARDCONTEXTX11 *pCtx, int retval)
     1606{
     1607    g_vboxDataRC = retval;
     1608    g_vboxDatapv = NULL;
     1609    g_vboxDatacb = 0;
     1610    VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 0);
     1611}
     1612
     1613/* Set the data in the simulated VBox clipboard. */
     1614static int clipSetVBoxUtf16(VBOXCLIPBOARDCONTEXTX11 *pCtx, int retval,
     1615                            const char *pcszData)
     1616{
     1617    PRTUTF16 pwszData = NULL;
     1618    size_t cwData = 0;
     1619    int rc = RTStrToUtf16Ex(pcszData, RTSTR_MAX, &pwszData, 0, &cwData);
     1620    if (RT_FAILURE(rc))
     1621        return rc;
     1622    size_t cb = cwData * 2 + 2;
     1623    void *pv = RTMemDup(pwszData, cb);
     1624    RTUtf16Free(pwszData);
     1625    if (pv == NULL)
     1626        return VERR_NO_MEMORY;
     1627    if (g_vboxDatapv)
     1628        RTMemFree(g_vboxDatapv);
     1629    g_vboxDataRC = retval;
     1630    g_vboxDatapv = pv;
     1631    g_vboxDatacb = cb;
     1632    VBoxX11ClipboardAnnounceVBoxFormat(pCtx,
     1633                                       VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     1634    return VINF_SUCCESS;
     1635}
     1636
     1637/* Return the data in the simulated VBox clipboard. */
    16071638int VBoxX11ClipboardReadVBoxData(VBOXCLIPBOARDCONTEXT *pCtx,
    16081639                                 uint32_t u32Format, void **ppv,
    16091640                                 uint32_t *pcb)
    16101641{
    1611     LogFlowFunc(("pCtx = %p\n", pCtx));
    1612     /* This should only ever be called for the second "test" clipboard. */
    1613     AssertReturn(pCtx == (VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11
    1614                          /* Magic cookie */, VERR_WRONG_ORDER);
    1615     /* Timeout test hack */
    1616     if (g_testTimeout)
    1617     {
    1618         RTThreadSleep(200);
    1619         /* Try to return data after we have been timed out. */
    1620         *ppv = RTMemDup((const void *) "Scribblings", sizeof("Scribblings"));
    1621         *pcb = sizeof("Scribblings");
    1622         LogFlowFunc(("sleep finished, returning\n"));
    1623         return VINF_SUCCESS;
    1624     }
    1625     /* Sanity. */
    1626     AssertReturn(g_testNum < MAX_TESTS, VERR_WRONG_ORDER);
    1627     testData *pData = &g_sTestData[g_testNum];
    1628     AssertPtrReturn(pData->getData(), VERR_NO_MEMORY);
    1629     AssertReturn(pData->getSize(), VERR_WRONG_ORDER);
    1630     void *retval = RTMemDup((const void *) pData->getData(),
    1631                             pData->getSize());
    1632     AssertPtrReturn(retval, VERR_NO_MEMORY);
    1633     *ppv = (void *) retval;
    1634     *pcb = pData->getSize();
    1635     LogFlowFunc(("returning\n"));
    1636     return VINF_SUCCESS;
    1637 }
    1638 
    1639 /** As long as our test is running, we grab back the clipboard if X11 ever
    1640  * tries to take it away.  I hope we don't end up with a tug of war... */
     1642    *pcb = g_vboxDatacb;
     1643    if (g_vboxDatapv != NULL)
     1644    {
     1645        void *pv = RTMemDup(g_vboxDatapv, g_vboxDatacb);
     1646        *ppv = pv;
     1647        return pv != NULL ? g_vboxDataRC : VERR_NO_MEMORY;
     1648    }
     1649    *ppv = NULL;
     1650    return g_vboxDataRC;
     1651}
     1652
     1653Display *XtDisplay(Widget w)
     1654{ return (Display *) 0xffff; }
     1655
     1656int XmbTextListToTextProperty(Display *display, char **list, int count,
     1657                              XICCEncodingStyle style,
     1658                              XTextProperty *text_prop_return)
     1659{
     1660    /* We don't fully reimplement this API for obvious reasons. */
     1661    AssertReturn(count == 1, XLocaleNotSupported);
     1662    AssertReturn(style == XCompoundTextStyle, XLocaleNotSupported);
     1663    /* We simplify the conversion by only accepting ASCII. */
     1664    for (unsigned i = 0; (*list)[i] != 0; ++i)
     1665        AssertReturn(((*list)[i] & 0x80) == 0, XLocaleNotSupported);
     1666    text_prop_return->value =
     1667            (unsigned char*)RTMemDup(*list, strlen(*list) + 1);
     1668    text_prop_return->encoding = clipGetAtom(NULL, "COMPOUND_TEXT");
     1669    text_prop_return->format = 8;
     1670    text_prop_return->nitems = strlen(*list);
     1671    return 0;
     1672}
     1673
     1674int Xutf8TextListToTextProperty(Display *display, char **list, int count,
     1675                                XICCEncodingStyle style,
     1676                                XTextProperty *text_prop_return)
     1677{
     1678    return XmbTextListToTextProperty(display, list, count, style,
     1679                                     text_prop_return);
     1680}
     1681
     1682int XmbTextPropertyToTextList(Display *display,
     1683                              const XTextProperty *text_prop,
     1684                              char ***list_return, int *count_return)
     1685{
     1686    int rc = 0;
     1687    if (text_prop->nitems == 0)
     1688    {
     1689        *list_return = NULL;
     1690        *count_return = 0;
     1691        return 0;
     1692    }
     1693    /* Only accept simple ASCII properties */
     1694    for (unsigned i = 0; i < text_prop->nitems; ++i)
     1695        AssertReturn(!(text_prop->value[i] & 0x80), XConverterNotFound);
     1696    char **ppList = (char **)RTMemAlloc(sizeof(char *));
     1697    char *pValue = (char *)RTMemDup(text_prop->value, text_prop->nitems + 1);
     1698    if (ppList)
     1699        *ppList = pValue;
     1700    if (!ppList || !pValue)
     1701    {
     1702        RTMemFree(ppList);
     1703        RTMemFree(pValue);
     1704        rc = XNoMemory;
     1705    }
     1706    else
     1707    {
     1708        /* NULL-terminate the string */
     1709        pValue[text_prop->nitems] = '\0';
     1710        *count_return = 1;
     1711        *list_return = ppList;
     1712    }
     1713    return rc;
     1714}
     1715
     1716int Xutf8TextPropertyToTextList(Display *display,
     1717                                const XTextProperty *text_prop,
     1718                                char ***list_return, int *count_return)
     1719{
     1720    return XmbTextPropertyToTextList(display, text_prop, list_return,
     1721                                     count_return);
     1722}
     1723
     1724void XtAppSetExitFlag(XtAppContext app_context) {}
     1725
     1726void XtDestroyWidget(Widget w) {}
     1727
     1728XtAppContext XtCreateApplicationContext(void) { return (XtAppContext)0xffff; }
     1729
     1730void XtDestroyApplicationContext(XtAppContext app_context) {}
     1731
     1732void XtToolkitInitialize(void) {}
     1733
     1734Boolean XtToolkitThreadInitialize(void) { return True; }
     1735
     1736Display *XtOpenDisplay(XtAppContext app_context,
     1737                       _Xconst _XtString display_string,
     1738                       _Xconst _XtString application_name,
     1739                       _Xconst _XtString application_class,
     1740                       XrmOptionDescRec *options, Cardinal num_options,
     1741                       int *argc, char **argv)
     1742{ return (Display *)0xffff; }
     1743
     1744Widget XtVaAppCreateShell(_Xconst _XtString application_name,
     1745                          _Xconst _XtString application_class,
     1746                          WidgetClass widget_class, Display *display, ...)
     1747{ return TEST_WIDGET; }
     1748
     1749void XtSetMappedWhenManaged(Widget widget, _XtBoolean mapped_when_managed) {}
     1750
     1751void XtRealizeWidget(Widget widget) {}
     1752
     1753XtInputId XtAppAddInput(XtAppContext app_context, int source,
     1754                        XtPointer condition, XtInputCallbackProc proc,
     1755                        XtPointer closure)
     1756{ return 0xffff; }
     1757
     1758/* Atoms we need other than the formats we support. */
     1759static const char *g_apszSupAtoms[] =
     1760{
     1761    "PRIMARY", "CLIPBOARD", "TARGETS", "MULTIPLE", "TIMESTAMP"
     1762};
     1763
     1764/* This just looks for the atom names in a couple of tables and returns an
     1765 * index with an offset added. */
     1766Boolean XtConvertAndStore(Widget widget, _Xconst _XtString from_type,
     1767                          XrmValue* from, _Xconst _XtString to_type,
     1768                          XrmValue* to_in_out)
     1769{
     1770    Boolean rc = False;
     1771    /* What we support is: */
     1772    AssertReturn(from_type == XtRString, False);
     1773    AssertReturn(to_type == XtRAtom, False);
     1774    for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)
     1775        if (!strcmp(from->addr, g_aFormats[i].pcszAtom))
     1776        {
     1777            *(Atom *)(to_in_out->addr) = (Atom) (i + 0x1000);
     1778            rc = True;
     1779        }
     1780    for (unsigned i = 0; i < RT_ELEMENTS(g_apszSupAtoms); ++i)
     1781        if (!strcmp(from->addr, g_apszSupAtoms[i]))
     1782        {
     1783            *(Atom *)(to_in_out->addr) = (Atom) (i + 0x2000);
     1784            rc = True;
     1785        }
     1786    Assert(rc == True);  /* Have we missed any atoms? */
     1787    return rc;
     1788}
     1789
     1790/* The current values of the X selection, which will be returned to the
     1791 * XtGetSelectionValue callback. */
     1792static Atom g_selTarget = 0;
     1793static Atom g_selType = 0;
     1794static const void *g_pSelData = NULL;
     1795static unsigned long g_cSelData = 0;
     1796static int g_selFormat = 0;
     1797
     1798void XtGetSelectionValue(Widget widget, Atom selection, Atom target,
     1799                         XtSelectionCallbackProc callback,
     1800                         XtPointer closure, Time time)
     1801{
     1802    unsigned long count = 0;
     1803    int format = 0;
     1804    Atom type = XA_STRING;
     1805    if (   (   selection != clipGetAtom(NULL, "PRIMARY")
     1806            && selection != clipGetAtom(NULL, "CLIPBOARD")
     1807            && selection != clipGetAtom(NULL, "TARGETS"))
     1808        || (   target != g_selTarget
     1809            && target != clipGetAtom(NULL, "TARGETS")))
     1810    {
     1811        /* Otherwise this is probably a caller error. */
     1812        Assert(target != g_selTarget);
     1813        callback(NULL, closure, &selection, &type, NULL, &count, &format);
     1814                /* Could not convert to target. */
     1815        return;
     1816    }
     1817    XtPointer pValue = NULL;
     1818    if (target == clipGetAtom(NULL, "TARGETS"))
     1819    {
     1820        pValue = (XtPointer) RTMemDup(&g_selTarget, sizeof(g_selTarget));
     1821        type = XA_ATOM;
     1822        count = 1;
     1823        format = 32;
     1824    }
     1825    else
     1826    {
     1827        pValue = (XtPointer) g_pSelData ? RTMemDup(g_pSelData, g_cSelData)
     1828                                        : NULL;
     1829        type = g_selType;
     1830        count = g_pSelData ? g_cSelData : 0;
     1831        format = g_selFormat;
     1832    }
     1833    if (!pValue)
     1834    {
     1835        count = 0;
     1836        format = 0;
     1837    }
     1838    callback(NULL, closure, &selection, &type, pValue,
     1839             &count, &format);
     1840}
     1841
     1842/* The formats currently on offer from X11 via the shared clipboard */
     1843static uint32_t g_fX11Formats = 0;
     1844
     1845void VBoxX11ClipboardReportX11Formats(VBOXCLIPBOARDCONTEXT* pCtx,
     1846                                      uint32_t u32Formats)
     1847{
     1848    g_fX11Formats = u32Formats;
     1849}
     1850
     1851static uint32_t clipQueryFormats()
     1852{
     1853    return g_fX11Formats;
     1854}
     1855
     1856/* Does our clipboard code currently own the selection? */
     1857static bool g_ownsSel = false;
     1858/* The procedure that is called when we should convert the selection to a
     1859 * given format. */
     1860static XtConvertSelectionProc g_pfnSelConvert = NULL;
     1861/* The procedure which is called when we lose the selection. */
     1862static XtLoseSelectionProc g_pfnSelLose = NULL;
     1863/* The procedure which is called when the selection transfer has completed. */
     1864static XtSelectionDoneProc g_pfnSelDone = NULL;
     1865
     1866Boolean XtOwnSelection(Widget widget, Atom selection, Time time,
     1867                       XtConvertSelectionProc convert,
     1868                       XtLoseSelectionProc lose,
     1869                       XtSelectionDoneProc done)
     1870{
     1871    if (selection != clipGetAtom(NULL, "CLIPBOARD"))
     1872        return True;  /* We don't really care about this. */
     1873    g_ownsSel = true;  /* Always succeed. */
     1874    g_pfnSelConvert = convert;
     1875    g_pfnSelLose = lose;
     1876    g_pfnSelDone = done;
     1877    return True;
     1878}
     1879
     1880void XtDisownSelection(Widget widget, Atom selection, Time time)
     1881{
     1882    g_ownsSel = false;
     1883    g_pfnSelConvert = NULL;
     1884    g_pfnSelLose = NULL;
     1885    g_pfnSelDone = NULL;
     1886}
     1887
     1888/* Request the shared clipboard to convert its data to a given format. */
     1889static bool clipConvertSelection(const char *pcszTarget, Atom *type,
     1890                                 XtPointer *value, unsigned long *length,
     1891                                 int *format)
     1892{
     1893    Atom target = clipGetAtom(NULL, pcszTarget);
     1894    if (target == 0)
     1895        return false;
     1896    /* Initialise all return values in case we make a quick exit. */
     1897    *type = XA_STRING;
     1898    *value = NULL;
     1899    *length = 0;
     1900    *format = 0;
     1901    if (!g_ownsSel)
     1902        return false;
     1903    if (!g_pfnSelConvert)
     1904        return false;
     1905    Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD");
     1906    if (!g_pfnSelConvert(TEST_WIDGET, &clipAtom, &target, type,
     1907                         value, length, format))
     1908        return false;
     1909    if (g_pfnSelDone)
     1910        g_pfnSelDone(TEST_WIDGET, &clipAtom, &target);
     1911    return true;
     1912}
     1913
     1914/* Set the current X selection data */
     1915static void clipSetSelectionValues(const char *pcszTarget, Atom type,
     1916                                   const void *data,
     1917                                   unsigned long count, int format)
     1918{
     1919    Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD");
     1920    g_selTarget = clipGetAtom(NULL, pcszTarget);
     1921    g_selType = type;
     1922    g_pSelData = data;
     1923    g_cSelData = count;
     1924    g_selFormat = format;
     1925    if (g_pfnSelLose)
     1926        g_pfnSelLose(TEST_WIDGET, &clipAtom);
     1927    g_ownsSel = false;
     1928    g_fX11Formats = 0;
     1929}
     1930
     1931char *XtMalloc(Cardinal size) { return (char *) RTMemAlloc(size); }
     1932
     1933char *XGetAtomName(Display *display, Atom atom)
     1934{
     1935    AssertReturn((unsigned)atom < RT_ELEMENTS(g_aFormats) + 1, NULL);
     1936    const char *pcszName = NULL;
     1937    if (atom < 0x1000)
     1938        return NULL;
     1939    else if (0x1000 <= atom && atom < 0x2000)
     1940    {
     1941        unsigned index = atom - 0x1000;
     1942        AssertReturn(index < RT_ELEMENTS(g_aFormats), NULL);
     1943        pcszName = g_aFormats[index].pcszAtom;
     1944    }
     1945    else
     1946    {
     1947        unsigned index = atom - 0x2000;
     1948        AssertReturn(index < RT_ELEMENTS(g_apszSupAtoms), NULL);
     1949        pcszName = g_apszSupAtoms[index];
     1950    }
     1951    return (char *)RTMemDup(pcszName, sizeof(pcszName) + 1);
     1952}
     1953
     1954int XFree(void *data)
     1955{
     1956    RTMemFree(data);
     1957    return 0;
     1958}
     1959
     1960void XFreeStringList(char **list)
     1961{
     1962    if (list)
     1963        RTMemFree(*list);
     1964    RTMemFree(list);
     1965}
     1966
     1967const char XtStrings [] = "";
     1968_WidgetClassRec* applicationShellWidgetClass;
     1969const char XtShellStrings [] = "";
     1970
     1971#define MAX_BUF_SIZE 256
     1972
     1973static bool testStringFromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx, uint32_t cbBuf,
     1974                              const char *pcszExp, int rcExp)
     1975{
     1976    bool retval = false;
     1977    AssertReturn(cbBuf <= MAX_BUF_SIZE, false);
     1978    if (!clipPollTargets())
     1979        RTPrintf("Failed to poll for targets\n");
     1980    else if (clipQueryFormats() != VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     1981        RTPrintf("Wrong targets reported: %02X\n", clipQueryFormats());
     1982    else
     1983    {
     1984        char pc[MAX_BUF_SIZE];
     1985        uint32_t cbActual;
     1986        int rc = VBoxX11ClipboardReadX11Data(pCtx,
     1987                                     VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
     1988                                     (void *) pc, cbBuf, &cbActual);
     1989        if (rc != rcExp)
     1990            RTPrintf("Wrong return code, expected %Rrc, got %Rrc\n", rcExp,
     1991                     rc);
     1992        else if (RT_FAILURE(rcExp))
     1993            retval = true;
     1994        else
     1995        {
     1996            RTUTF16 wcExp[MAX_BUF_SIZE / 2];
     1997            RTUTF16 *pwcExp = wcExp;
     1998            size_t cwc = 0;
     1999            rc = RTStrToUtf16Ex(pcszExp, RTSTR_MAX, &pwcExp,
     2000                                RT_ELEMENTS(wcExp), &cwc);
     2001            size_t cbExp = cwc * 2 + 2;
     2002            AssertRC(rc);
     2003            if (RT_SUCCESS(rc))
     2004            {
     2005                if (cbActual != cbExp)
     2006                {
     2007                    RTPrintf("Returned string is the wrong size, string \"%.*ls\", size %u\n",
     2008                             RT_MIN(MAX_BUF_SIZE, cbActual), pc, cbActual);
     2009                    RTPrintf("Expected \"%s\", size %u\n", pcszExp,
     2010                             cbExp);
     2011                }
     2012                else
     2013                {
     2014                    if (memcmp(pc, wcExp, cbExp) == 0)
     2015                        retval = true;
     2016                    else
     2017                        RTPrintf("Returned string \"%.*ls\" does not match expected string \"%s\"\n",
     2018                                 MAX_BUF_SIZE, pc, pcszExp);
     2019                }
     2020            }
     2021        }
     2022    }
     2023    if (!retval)
     2024        RTPrintf("Expected: string \"%s\", rc %Rrc (buffer size %u)\n",
     2025                 pcszExp, rcExp, cbBuf);
     2026    return retval;
     2027}
     2028
     2029static bool testStringFromVBox(VBOXCLIPBOARDCONTEXTX11 *pCtx,
     2030                               const char *pcszTarget, Atom typeExp,
     2031                               const void *valueExp, unsigned long lenExp,
     2032                               int formatExp)
     2033{
     2034    bool retval = false;
     2035    Atom type;
     2036    XtPointer value = NULL;
     2037    unsigned long length;
     2038    int format;
     2039    if (clipConvertSelection(pcszTarget, &type, &value, &length, &format))
     2040    {
     2041        if (   type != typeExp
     2042            || length != lenExp
     2043            || format != formatExp
     2044            || memcmp((const void *) value, (const void *)valueExp,
     2045                      lenExp))
     2046        {
     2047            RTPrintf("Bad data: type %d, (expected %d), length %u, (%u), format %d (%d),\n",
     2048                     type, typeExp, length, lenExp, format, formatExp);
     2049            RTPrintf("value \"%.*s\" (\"%.*s\")", RT_MIN(length, 20), value,
     2050                     RT_MIN(lenExp, 20), valueExp);
     2051        }
     2052        else
     2053            retval = true;
     2054    }
     2055    else
     2056        RTPrintf("Conversion failed\n");
     2057    XtFree((char *)value);
     2058    if (!retval)
     2059        RTPrintf("Conversion to %s, expected \"%s\"\n", pcszTarget, valueExp);
     2060    return retval;
     2061}
     2062
     2063static bool testStringFromVBoxFailed(VBOXCLIPBOARDCONTEXTX11 *pCtx,
     2064                                     const char *pcszTarget)
     2065{
     2066    bool retval = false;
     2067    Atom type;
     2068    XtPointer value = NULL;
     2069    unsigned long length;
     2070    int format;
     2071    if (!clipConvertSelection(pcszTarget, &type, &value, &length, &format))
     2072        retval = true;
     2073    XtFree((char *)value);
     2074    if (!retval)
     2075    {
     2076        RTPrintf("Conversion to target %s, should have failed but didn't\n",
     2077                 pcszTarget);
     2078        RTPrintf("Returned type %d, length %u, format %d, value \"%.*s\"\n",
     2079                 type, length, format, RT_MIN(length, 20), value);
     2080    }
     2081    return retval;
     2082}
     2083
     2084int main()
     2085{
     2086    RTR3Init();
     2087    VBOXCLIPBOARDCONTEXTX11 *pCtx = VBoxX11ClipboardConstructX11(NULL);
     2088    unsigned cErrs = 0;
     2089    char pc[MAX_BUF_SIZE];
     2090    uint32_t cbActual;
     2091    int rc = VBoxX11ClipboardStartX11(pCtx);
     2092    AssertRCReturn(rc, 1);
     2093
     2094    /***********/
     2095    RTPrintf(TEST_NAME ": TESTING reading Utf-8 from X11\n");
     2096    clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
     2097                           sizeof("hello world"), 8);
     2098    if (!testStringFromX11(pCtx, 256, "hello world", VINF_SUCCESS))
     2099        ++cErrs;
     2100    if (!testStringFromX11(pCtx, sizeof("hello world") * 2, "hello world",
     2101                           VINF_SUCCESS))
     2102        ++cErrs;
     2103    if (!testStringFromX11(pCtx, sizeof("hello world") * 2 - 1, "hello world",
     2104                           VERR_BUFFER_OVERFLOW))
     2105        ++cErrs;
     2106    if (!testStringFromX11(pCtx, 0, "hello world", VERR_BUFFER_OVERFLOW))
     2107        ++cErrs;
     2108    clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world\n",
     2109                           sizeof("hello world\n"), 8);
     2110    if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2,
     2111                           "hello world\r\n", VINF_SUCCESS))
     2112        ++cErrs;
     2113    clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world\n",
     2114                           sizeof("hello world\n"), 8);
     2115    if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2,
     2116                           "hello world\r\n", VINF_SUCCESS))
     2117        ++cErrs;
     2118    clipSetSelectionValues("UTF8_STRING", XA_STRING, "",
     2119                           sizeof(""), 8);
     2120    if (!testStringFromX11(pCtx, sizeof("") * 2, "", VINF_SUCCESS))
     2121        ++cErrs;
     2122    /* This next one is Utf-8 only. */
     2123    clipSetSelectionValues("UTF8_STRING", XA_STRING,
     2124                           "100\xE2\x82\xAC" /* 100 Euro */,
     2125                           sizeof("100\xE2\x82\xAC"), 8);
     2126    if (!testStringFromX11(pCtx, sizeof("100\xE2\x82\xAC") * 2,
     2127                           "100\xE2\x82\xAC", VINF_SUCCESS))
     2128        ++cErrs;
     2129
     2130    /***********/
     2131    RTPrintf(TEST_NAME ": TESTING reading compound text from X11\n");
     2132    clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world",
     2133                           sizeof("hello world"), 8);
     2134    if (!testStringFromX11(pCtx, 256, "hello world", VINF_SUCCESS))
     2135        ++cErrs;
     2136    if (!testStringFromX11(pCtx, sizeof("hello world") * 2, "hello world",
     2137                           VINF_SUCCESS))
     2138        ++cErrs;
     2139    if (!testStringFromX11(pCtx, sizeof("hello world") * 2 - 1, "hello world",
     2140                           VERR_BUFFER_OVERFLOW))
     2141        ++cErrs;
     2142    if (!testStringFromX11(pCtx, 0, "hello world", VERR_BUFFER_OVERFLOW))
     2143        ++cErrs;
     2144    clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world\n",
     2145                           sizeof("hello world\n"), 8);
     2146    if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2,
     2147                           "hello world\r\n", VINF_SUCCESS))
     2148        ++cErrs;
     2149    clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world\n",
     2150                           sizeof("hello world\n"), 8);
     2151    if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2,
     2152                           "hello world\r\n", VINF_SUCCESS))
     2153        ++cErrs;
     2154    clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "",
     2155                           sizeof(""), 8);
     2156    if (!testStringFromX11(pCtx, sizeof("") * 2, "", VINF_SUCCESS))
     2157        ++cErrs;
     2158
     2159    /***********/
     2160    RTPrintf(TEST_NAME ": TESTING X11 timeout\n");
     2161    clipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, "hello world",
     2162                           sizeof("hello world"), 8);
     2163    if (!testStringFromX11(pCtx, 256, "hello world", VERR_TIMEOUT))
     2164        ++cErrs;
     2165
     2166    /***********/
     2167    RTPrintf(TEST_NAME ": TESTING a data request from an empty X11 clipboard\n");
     2168    clipSetSelectionValues("UTF8_STRING", XA_STRING, NULL,
     2169                           0, 8);
     2170    rc = VBoxX11ClipboardReadX11Data(pCtx,
     2171                                     VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
     2172                                     (void *) pc, sizeof(pc), &cbActual);
     2173    if (rc != VERR_NO_DATA)
     2174    {
     2175        RTPrintf("Returned %Rrc instead of VERR_NO_DATA\n", rc);
     2176        ++cErrs;
     2177    }
     2178
     2179    /***********/
     2180    RTPrintf(TEST_NAME ": TESTING a request for an invalid host format from X11\n");
     2181    rc = VBoxX11ClipboardReadX11Data(pCtx, 0xffff, (void *) pc,
     2182                                     sizeof(pc), &cbActual);
     2183    if (rc != VERR_NOT_IMPLEMENTED)
     2184    {
     2185        RTPrintf("Returned %Rrc instead of VERR_NOT_IMPLEMENTED\n", rc);
     2186        ++cErrs;
     2187    }
     2188
     2189    /***********/
     2190    RTPrintf(TEST_NAME ": TESTING reading Utf-8 from VBox\n");
     2191    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world");
     2192    if (!testStringFromVBox(pCtx, "UTF8_STRING",
     2193                            clipGetAtom(NULL, "UTF8_STRING"),
     2194                            "hello world", sizeof("hello world"), 8))
     2195        ++cErrs;
     2196    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world\r\n");
     2197    if (!testStringFromVBox(pCtx, "UTF8_STRING",
     2198                            clipGetAtom(NULL, "UTF8_STRING"),
     2199                            "hello world\n", sizeof("hello world\n"), 8))
     2200        ++cErrs;
     2201    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "");
     2202    if (!testStringFromVBox(pCtx, "UTF8_STRING",
     2203                            clipGetAtom(NULL, "UTF8_STRING"),
     2204                            "", sizeof(""), 8))
     2205        ++cErrs;
     2206    /* This next one is Utf-8 only. */
     2207    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */);
     2208    if (!testStringFromVBox(pCtx, "UTF8_STRING",
     2209                            clipGetAtom(NULL, "UTF8_STRING"),
     2210                            "100\xE2\x82\xAC", sizeof("100\xE2\x82\xAC"), 8))
     2211        ++cErrs;
     2212
     2213    /***********/
     2214    RTPrintf(TEST_NAME ": TESTING reading COMPOUND TEXT from VBox\n");
     2215    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world");
     2216    if (!testStringFromVBox(pCtx, "COMPOUND_TEXT",
     2217                            clipGetAtom(NULL, "COMPOUND_TEXT"),
     2218                            "hello world", sizeof("hello world"), 8))
     2219        ++cErrs;
     2220    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world\r\n");
     2221    if (!testStringFromVBox(pCtx, "COMPOUND_TEXT",
     2222                            clipGetAtom(NULL, "COMPOUND_TEXT"),
     2223                            "hello world\n", sizeof("hello world\n"), 8))
     2224        ++cErrs;
     2225    clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "");
     2226    if (!testStringFromVBox(pCtx, "COMPOUND_TEXT",
     2227                            clipGetAtom(NULL, "COMPOUND_TEXT"),
     2228                            "", sizeof(""), 8))
     2229        ++cErrs;
     2230
     2231    /***********/
     2232    RTPrintf(TEST_NAME ": TESTING reading from VBox with timeout\n");
     2233    clipEmptyVBox(pCtx, VERR_TIMEOUT);
     2234    if (!testStringFromVBoxFailed(pCtx, "UTF8_STRING"))
     2235        ++cErrs;
     2236
     2237    /***********/
     2238    RTPrintf(TEST_NAME ": TESTING reading from VBox with no data\n");
     2239    clipEmptyVBox(pCtx, VINF_SUCCESS);
     2240    if (!testStringFromVBoxFailed(pCtx, "UTF8_STRING"))
     2241        ++cErrs;
     2242    if (cErrs > 0)
     2243        RTPrintf("Failed with %u error(s)\n", cErrs);
     2244    return cErrs > 0 ? 1 : 0;
     2245}
     2246
     2247#endif
     2248
     2249#ifdef SMOKETEST
     2250
     2251/* This is a simple test case that just starts a copy of the X11 clipboard
     2252 * backend, checks the X11 clipboard and exits.  If ever needed I will add an
     2253 * interactive mode in which the user can read and copy to the clipboard from
     2254 * the command line. */
     2255
     2256#include <iprt/initterm.h>
     2257#include <iprt/stream.h>
     2258
     2259#define TEST_NAME "tstClipboardX11Smoke"
     2260
     2261int VBoxX11ClipboardReadVBoxData(VBOXCLIPBOARDCONTEXT *pCtx,
     2262                                 uint32_t u32Format, void **ppv,
     2263                                 uint32_t *pcb)
     2264{
     2265    return VERR_NO_DATA;
     2266}
     2267
    16412268void VBoxX11ClipboardReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx,
    16422269                                      uint32_t u32Formats)
    1643 {
    1644     LogFlowFunc(("pCtx = %p\n", pCtx));
    1645     if (pCtx == (VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11) /* Magic cookie */
    1646         VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox,
    1647                         VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
    1648 }
    1649 
    1650 /** Initial tests that can be done while the clipboard contents are still
    1651  * invalid.
    1652  * @returns boolean success value
    1653  * @note    prints status information to stdout
    1654  */
    1655 bool testInvalid(void)
    1656 {
    1657     bool fSuccess = true;
    1658     char pc[256];
    1659     uint32_t cbActual;
    1660     RTPrintf("tstClipboardX11:  TESTING a request for an invalid data format\n");
    1661     int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 0xffff, (void *) pc,
    1662                                          sizeof(pc), &cbActual);
    1663     RTPrintf("Returned %Rrc - %s\n", rc,
    1664              rc == VERR_NOT_IMPLEMENTED ? "SUCCESS" : "FAILURE");
    1665     if (rc != VERR_NOT_IMPLEMENTED)
    1666         fSuccess = false;
    1667     RTPrintf("tstClipboardX11:  TESTING a request for data from an empty clipboard\n");
    1668     VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestX11,
    1669                                       VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
    1670     VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestX11,
    1671                                        0);
    1672     rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
    1673                                      VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
    1674                                      (void *) pc, sizeof(pc), &cbActual);
    1675     RTPrintf("Returned %Rrc - %s\n", rc,
    1676              rc == VERR_NO_DATA ? "SUCCESS" : "FAILURE");
    1677     if (rc != VERR_NO_DATA)
    1678         fSuccess = false;
    1679     return fSuccess;
    1680 }
    1681 
    1682 /** Tests an entry in the table above.
    1683  * @returns boolean success value
    1684  * @note    prints status information to stdout
    1685  */
    1686 bool testEntry(testData *pData)
    1687 {
    1688     bool fSuccess = false;
    1689     char pc[256];
    1690     uint32_t cbActual;
    1691     for (int i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i)
    1692     {
    1693         VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox,
    1694                                       VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
    1695         int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
    1696                         VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
    1697                                              (void *) pc, sizeof(pc),
    1698                                              &cbActual);
    1699         AssertRCReturn(rc, 1);
    1700         /* Did we expect and get an overflow? */
    1701         if (   RT_SUCCESS(rc)
    1702             && (cbActual == pData->getSize())
    1703             && pData->overflow())
    1704             fSuccess = true;
    1705         /* Did we expect a string and get it? */
    1706         else if (   RT_SUCCESS(rc)
    1707                  && (memcmp(pc, pData->getData(),
    1708                             pData->getSize()) == 0))
    1709             fSuccess = true;
    1710         else
    1711             RTThreadSleep(50);
    1712         if (fSuccess)
    1713             RTPrintf("text %ls, %sretval %Rrc - SUCCESS\n",
    1714                      pData->getData(),
    1715                      pData->overflow() ? "buffer overflow as expected, "
    1716                                        : "", rc);
    1717         else
    1718             RTPrintf("text %ls, retval %Rrc, attempt %d of %d\n",
    1719                      pData->getData(), rc, i + 1,
    1720                      MAX_ATTEMPTS);
    1721     }
    1722     if (!fSuccess)
    1723         RTPrintf("FAILURE.  Last string obtained was %.*lS\n",
    1724                  RT_MIN(cbActual / 2, 20), pc);
    1725     return fSuccess;
    1726 }
     2270{}
    17272271
    17282272int main()
    17292273{
    17302274    int rc = VINF_SUCCESS;
    1731     int status = 0;
    1732     g_debugClipboard = true;
     2275    RTR3Init();
    17332276    /* We can't test anything without an X session, so just return success
    17342277     * in that case. */
    17352278    if (!RTEnvGet("DISPLAY"))
     2279    {
     2280        RTPrintf(TEST_NAME ": X11 not available, not running test\n");
    17362281        return 0;
    1737     RTR3Init();
    1738     g_pCtxTestX11 = VBoxX11ClipboardConstructX11(NULL);
    1739     g_pCtxTestVBox =
    1740         VBoxX11ClipboardConstructX11((VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11);
    1741     rc = VBoxX11ClipboardStartX11(g_pCtxTestVBox);
     2282    }
     2283    RTPrintf(TEST_NAME ": TESTING\n");
     2284    VBOXCLIPBOARDCONTEXTX11 *pCtx = VBoxX11ClipboardConstructX11(NULL);
     2285    AssertReturn(pCtx, 1);
     2286    rc = VBoxX11ClipboardStartX11(pCtx);
    17422287    AssertRCReturn(rc, 1);
    1743     bool fSuccess = false;
    1744     /* Test a request for an invalid data format and data from an empty
    1745      * clipboard */
    1746     for (unsigned i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i)
    1747     {
    1748         rc = VBoxX11ClipboardStartX11(g_pCtxTestX11);
    1749         AssertRCReturn(rc, 1);
    1750         fSuccess = testInvalid();
    1751         VBoxX11ClipboardStopX11(g_pCtxTestX11);
    1752         if (!fSuccess)
    1753         {
    1754             RTPrintf("attempt %d of %d\n", i + 1, MAX_ATTEMPTS + 1);
    1755             RTThreadSleep(50);
    1756         }
    1757     }
    1758     if (!fSuccess)
    1759         status = 1;
    1760     rc = VBoxX11ClipboardStartX11(g_pCtxTestX11);
     2288    /* Give the clipboard time to synchronise. */
     2289    RTThreadSleep(500);
     2290    rc = VBoxX11ClipboardStopX11(pCtx);
    17612291    AssertRCReturn(rc, 1);
    1762     /* Claim the clipboard and make sure we get it */
    1763     VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox,
    1764                     VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
    1765     for (unsigned i = 0;
    1766             i < 255
    1767          && g_pCtxTestX11->X11TextFormat == INVALID;
    1768          ++i)
    1769         RTThreadSleep(50);
    1770     AssertReturn(g_pCtxTestX11->X11TextFormat != INVALID, 1);
    1771     /* Do general purpose clipboard tests */
    1772     for (int i = 0; i < 2; ++i)
    1773     {
    1774         g_testUtf8 = (i == 0);
    1775         g_testCText = (i == 1);
    1776         RTPrintf("tstClipboardX11: TESTING sending and receiving of %s\n",
    1777                  i == 0 ? "Utf-8" : "COMPOUND TEXT");
    1778         for (g_testNum = 0; g_testNum < MAX_TESTS; ++g_testNum)
    1779         {
    1780             if (!testEntry(&g_sTestData[g_testNum]))
    1781                 status = 1;
    1782         }
    1783     }
    1784     /* Finally test timeouts. */
    1785     XtAppSetSelectionTimeout(g_pCtxTestX11->appContext, 10);
    1786     RTPrintf("tstClipboardX11: TESTING the clipboard timeout\n");
    1787     rc = VINF_SUCCESS;
    1788     g_testTimeout = true;
    1789     for (unsigned i = 0; (i < MAX_ATTEMPTS) && (rc != VERR_TIMEOUT); ++i)
    1790     {
    1791         char pc[256];
    1792         uint32_t cbActual;
    1793         VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox,
    1794                                       VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
    1795         rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11,
    1796                     VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
    1797                                          (void *) pc, sizeof(pc), &cbActual);
    1798         AssertMsg(   RT_SUCCESS(rc)
    1799                   || (rc == VERR_TIMEOUT)
    1800                   || (rc == VERR_NO_DATA),
    1801                   ("rc = %Rrc\n", rc));
    1802         if (rc == VERR_TIMEOUT)
    1803             RTPrintf("SUCCESS\n");
    1804         else
    1805         {
    1806             RTPrintf("Attempt %d of %d\n", i + 1, MAX_ATTEMPTS);
    1807             RTThreadSleep(50);
    1808         }
    1809     }
    1810     if (rc != VERR_TIMEOUT)
    1811         status = 1;
    1812     rc = VBoxX11ClipboardStopX11(g_pCtxTestX11);
    1813     AssertRCReturn(rc, 1);
    1814     rc = VBoxX11ClipboardStopX11(g_pCtxTestVBox);
    1815     AssertRCReturn(rc, 1);
    1816     VBoxX11ClipboardDestructX11(g_pCtxTestX11);
    1817     VBoxX11ClipboardDestructX11(g_pCtxTestVBox);
    1818     return status;
    1819 }
    1820 
    1821 #endif /* TESTCASE defined */
     2292    VBoxX11ClipboardDestructX11(pCtx);
     2293    return 0;
     2294}
     2295
     2296#endif /* SMOKETEST defined */
Note: See TracChangeset for help on using the changeset viewer.

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