1/**
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 *  Permission is hereby granted, free of charge, to any person obtaining a
5 *  copy of this software and associated documentation files (the "Software"),
6 *  to deal in the Software without restriction, including without limitation
7 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 *  and/or sell copies of the Software, and to permit persons to whom the
9 *  Software is furnished to do so, subject to the following conditions:
10 *
11 *  The above copyright notice and this permission notice (including the next
12 *  paragraph) shall be included in all copies or substantial portions of the
13 *  Software.
14 *
15 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 *  DEALINGS IN THE SOFTWARE.
22 */
23
24/* Test relies on assert() */
25#undef NDEBUG
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdint.h>
32#include <X11/X.h>
33#include <X11/Xproto.h>
34#include <X11/extensions/XI2proto.h>
35#include <X11/Xatom.h>
36#include "inputstr.h"
37#include "extinit.h"
38#include "exglobals.h"
39#include "scrnintstr.h"
40#include "xkbsrv.h"
41
42#include "xiquerydevice.h"
43
44#include "protocol-common.h"
45/*
46 * Protocol testing for XIQueryDevice request and reply.
47 *
48 * Test approach:
49 * Wrap WriteToClient to intercept server's reply. ProcXIQueryDevice returns
50 * data in two batches, once for the request, once for the trailing data
51 * with the device information.
52 * Repeatedly test with varying deviceids and check against data in reply.
53 */
54
55struct test_data {
56    int which_device;
57    int num_devices_in_reply;
58};
59
60extern ClientRec client_window;
61
62static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data,
63                                     void *closure);
64static void reply_XIQueryDevice(ClientPtr client, int len, char *data,
65                                void *closure);
66
67/* reply handling for the first bytes that constitute the reply */
68static void
69reply_XIQueryDevice(ClientPtr client, int len, char *data, void *userdata)
70{
71    xXIQueryDeviceReply *rep = (xXIQueryDeviceReply *) data;
72    struct test_data *querydata = (struct test_data *) userdata;
73
74    if (client->swapped) {
75        swapl(&rep->length);
76        swaps(&rep->sequenceNumber);
77        swaps(&rep->num_devices);
78    }
79
80    reply_check_defaults(rep, len, XIQueryDevice);
81
82    if (querydata->which_device == XIAllDevices)
83        assert(rep->num_devices == devices.num_devices);
84    else if (querydata->which_device == XIAllMasterDevices)
85        assert(rep->num_devices == devices.num_master_devices);
86    else
87        assert(rep->num_devices == 1);
88
89    querydata->num_devices_in_reply = rep->num_devices;
90    reply_handler = reply_XIQueryDevice_data;
91}
92
93/* reply handling for the trailing bytes that constitute the device info */
94static void
95reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void *closure)
96{
97    int i, j;
98    struct test_data *querydata = (struct test_data *) closure;
99
100    DeviceIntPtr dev;
101    xXIDeviceInfo *info = (xXIDeviceInfo *) data;
102    xXIAnyInfo *any;
103
104    for (i = 0; i < querydata->num_devices_in_reply; i++) {
105        if (client->swapped) {
106            swaps(&info->deviceid);
107            swaps(&info->attachment);
108            swaps(&info->use);
109            swaps(&info->num_classes);
110            swaps(&info->name_len);
111        }
112
113        if (querydata->which_device > XIAllMasterDevices)
114            assert(info->deviceid == querydata->which_device);
115
116        assert(info->deviceid >= 2);    /* 0 and 1 is reserved */
117
118        switch (info->deviceid) {
119        case 2:                /* VCP */
120            dev = devices.vcp;
121            assert(info->use == XIMasterPointer);
122            assert(info->attachment == devices.vck->id);
123            assert(info->num_classes == 3);     /* 2 axes + button */
124            break;
125        case 3:                /* VCK */
126            dev = devices.vck;
127            assert(info->use == XIMasterKeyboard);
128            assert(info->attachment == devices.vcp->id);
129            assert(info->num_classes == 1);
130            break;
131        case 4:                /* mouse */
132            dev = devices.mouse;
133            assert(info->use == XISlavePointer);
134            assert(info->attachment == devices.vcp->id);
135            assert(info->num_classes == 7);     /* 4 axes + button + 2 scroll */
136            break;
137        case 5:                /* keyboard */
138            dev = devices.kbd;
139            assert(info->use == XISlaveKeyboard);
140            assert(info->attachment == devices.vck->id);
141            assert(info->num_classes == 1);
142            break;
143
144        default:
145            /* We shouldn't get here */
146            assert(0);
147            break;
148        }
149        assert(info->enabled == dev->enabled);
150        assert(info->name_len == strlen(dev->name));
151        assert(strncmp((char *) &info[1], dev->name, info->name_len) == 0);
152
153        any =
154            (xXIAnyInfo *) ((char *) &info[1] + ((info->name_len + 3) / 4) * 4);
155        for (j = 0; j < info->num_classes; j++) {
156            if (client->swapped) {
157                swaps(&any->type);
158                swaps(&any->length);
159                swaps(&any->sourceid);
160            }
161
162            switch (info->deviceid) {
163            case 3:            /* VCK and kbd have the same properties */
164            case 5:
165            {
166                int k;
167                xXIKeyInfo *ki = (xXIKeyInfo *) any;
168                XkbDescPtr xkb = devices.vck->key->xkbInfo->desc;
169                uint32_t *kc;
170
171                if (client->swapped)
172                    swaps(&ki->num_keycodes);
173
174                assert(any->type == XIKeyClass);
175                assert(ki->num_keycodes ==
176                       (xkb->max_key_code - xkb->min_key_code + 1));
177                assert(any->length == (2 + ki->num_keycodes));
178
179                kc = (uint32_t *) &ki[1];
180                for (k = 0; k < ki->num_keycodes; k++, kc++) {
181                    if (client->swapped)
182                        swapl(kc);
183
184                    assert(*kc >= xkb->min_key_code);
185                    assert(*kc <= xkb->max_key_code);
186                }
187                break;
188            }
189            case 4:
190            {
191                assert(any->type == XIButtonClass ||
192                       any->type == XIValuatorClass ||
193                       any->type == XIScrollClass);
194
195                if (any->type == XIScrollClass) {
196                    xXIScrollInfo *si = (xXIScrollInfo *) any;
197
198                    if (client->swapped) {
199                        swaps(&si->number);
200                        swaps(&si->scroll_type);
201                        swapl(&si->increment.integral);
202                        swapl(&si->increment.frac);
203                    }
204                    assert(si->length == 6);
205                    assert(si->number == 2 || si->number == 3);
206                    if (si->number == 2) {
207                        assert(si->scroll_type == XIScrollTypeVertical);
208                        assert(!si->flags);
209                    }
210                    if (si->number == 3) {
211                        assert(si->scroll_type == XIScrollTypeHorizontal);
212                        assert(si->flags & XIScrollFlagPreferred);
213                        assert(!(si->flags & ~XIScrollFlagPreferred));
214                    }
215
216                    assert(si->increment.integral == si->number);
217                    /* protocol-common.c sets up increments of 2.4 and 3.5 */
218                    assert(si->increment.frac > 0.3 * (1ULL << 32));
219                    assert(si->increment.frac < 0.6 * (1ULL << 32));
220                }
221
222            }
223                /* fall through */
224            case 2:            /* VCP and mouse have the same properties except for scroll */
225            {
226                if (info->deviceid == 2)        /* VCP */
227                    assert(any->type == XIButtonClass ||
228                           any->type == XIValuatorClass);
229
230                if (any->type == XIButtonClass) {
231                    int l;
232                    xXIButtonInfo *bi = (xXIButtonInfo *) any;
233
234                    if (client->swapped)
235                        swaps(&bi->num_buttons);
236
237                    assert(bi->num_buttons == devices.vcp->button->numButtons);
238
239                    l = 2 + bi->num_buttons +
240                        bytes_to_int32(bits_to_bytes(bi->num_buttons));
241                    assert(bi->length == l);
242                }
243                else if (any->type == XIValuatorClass) {
244                    xXIValuatorInfo *vi = (xXIValuatorInfo *) any;
245
246                    if (client->swapped) {
247                        swaps(&vi->number);
248                        swapl(&vi->label);
249                        swapl(&vi->min.integral);
250                        swapl(&vi->min.frac);
251                        swapl(&vi->max.integral);
252                        swapl(&vi->max.frac);
253                        swapl(&vi->resolution);
254                    }
255
256                    assert(vi->length == 11);
257                    assert(vi->number >= 0);
258                    assert(vi->number < 4);
259                    if (info->deviceid == 2)    /* VCP */
260                        assert(vi->number < 2);
261
262                    assert(vi->mode == XIModeRelative);
263                    /* device was set up as relative, so standard
264                     * values here. */
265                    assert(vi->min.integral == -1);
266                    assert(vi->min.frac == 0);
267                    assert(vi->max.integral == -1);
268                    assert(vi->max.frac == 0);
269                    assert(vi->resolution == 0);
270                }
271            }
272                break;
273            }
274            any = (xXIAnyInfo *) (((char *) any) + any->length * 4);
275        }
276
277        info = (xXIDeviceInfo *) any;
278    }
279}
280
281static void
282request_XIQueryDevice(struct test_data *querydata, int deviceid, int error)
283{
284    int rc;
285    ClientRec client;
286    xXIQueryDeviceReq request;
287
288    request_init(&request, XIQueryDevice);
289    client = init_client(request.length, &request);
290    reply_handler = reply_XIQueryDevice;
291
292    querydata->which_device = deviceid;
293
294    request.deviceid = deviceid;
295    rc = ProcXIQueryDevice(&client);
296    assert(rc == error);
297
298    if (rc != Success)
299        assert(client.errorValue == deviceid);
300
301    reply_handler = reply_XIQueryDevice;
302
303    client.swapped = TRUE;
304    swaps(&request.length);
305    swaps(&request.deviceid);
306    rc = SProcXIQueryDevice(&client);
307    assert(rc == error);
308
309    if (rc != Success)
310        assert(client.errorValue == deviceid);
311}
312
313static void
314test_XIQueryDevice(void)
315{
316    int i;
317    xXIQueryDeviceReq request;
318    struct test_data data;
319
320    reply_handler = reply_XIQueryDevice;
321    global_userdata = &data;
322    request_init(&request, XIQueryDevice);
323
324    printf("Testing XIAllDevices.\n");
325    request_XIQueryDevice(&data, XIAllDevices, Success);
326    printf("Testing XIAllMasterDevices.\n");
327    request_XIQueryDevice(&data, XIAllMasterDevices, Success);
328
329    printf("Testing existing device ids.\n");
330    for (i = 2; i < 6; i++)
331        request_XIQueryDevice(&data, i, Success);
332
333    printf("Testing non-existing device ids.\n");
334    for (i = 6; i <= 0xFFFF; i++)
335        request_XIQueryDevice(&data, i, BadDevice);
336
337    reply_handler = NULL;
338
339}
340
341int
342protocol_xiquerydevice_test(void)
343{
344    init_simple();
345
346    test_XIQueryDevice();
347
348    return 0;
349}
350