11.1Scgd/** 21.1Scgd * Copyright © 2009 Red Hat, Inc. 31.1Scgd * 41.1Scgd * Permission is hereby granted, free of charge, to any person obtaining a 51.1Scgd * copy of this software and associated documentation files (the "Software"), 61.1Scgd * to deal in the Software without restriction, including without limitation 71.1Scgd * the rights to use, copy, modify, merge, publish, distribute, sublicense, 81.1Scgd * and/or sell copies of the Software, and to permit persons to whom the 91.1Scgd * Software is furnished to do so, subject to the following conditions: 101.1Scgd * 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#ifdef HAVE_DIX_CONFIG_H 25#include <dix-config.h> 26#endif 27 28#include <stdint.h> 29#include <X11/X.h> 30#include <X11/Xproto.h> 31#include <X11/extensions/XI2proto.h> 32#include <X11/Xatom.h> 33#include "inputstr.h" 34#include "extinit.h" 35#include "scrnintstr.h" 36#include "xkbsrv.h" 37 38#include "xiquerydevice.h" 39 40#include "protocol-common.h" 41#include <glib.h> 42/* 43 * Protocol testing for XIQueryDevice request and reply. 44 * 45 * Test approach: 46 * Wrap WriteToClient to intercept server's reply. ProcXIQueryDevice returns 47 * data in two batches, once for the request, once for the trailing data 48 * with the device information. 49 * Repeatedly test with varying deviceids and check against data in reply. 50 */ 51 52struct test_data { 53 int which_device; 54 int num_devices_in_reply; 55}; 56 57static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void *userdata); 58static void reply_XIQueryDevice(ClientPtr client, int len, char* data, void *userdata); 59 60/* reply handling for the first bytes that constitute the reply */ 61static void reply_XIQueryDevice(ClientPtr client, int len, char* data, void *userdata) 62{ 63 xXIQueryDeviceReply *rep = (xXIQueryDeviceReply*)data; 64 struct test_data *querydata = (struct test_data*)userdata; 65 66 if (client->swapped) 67 { 68 char n; 69 swapl(&rep->length, n); 70 swaps(&rep->sequenceNumber, n); 71 swaps(&rep->num_devices, n); 72 } 73 74 reply_check_defaults(rep, len, XIQueryDevice); 75 76 if (querydata->which_device == XIAllDevices) 77 g_assert(rep->num_devices == devices.num_devices); 78 else if (querydata->which_device == XIAllMasterDevices) 79 g_assert(rep->num_devices == devices.num_master_devices); 80 else 81 g_assert(rep->num_devices == 1); 82 83 querydata->num_devices_in_reply = rep->num_devices; 84 reply_handler = reply_XIQueryDevice_data; 85} 86 87/* reply handling for the trailing bytes that constitute the device info */ 88static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void *userdata) 89{ 90 char n; 91 int i, j; 92 struct test_data *querydata = (struct test_data*)userdata; 93 94 DeviceIntPtr dev; 95 xXIDeviceInfo *info = (xXIDeviceInfo*)data; 96 xXIAnyInfo *any; 97 98 for (i = 0; i < querydata->num_devices_in_reply; i++) 99 { 100 if (client->swapped) 101 { 102 swaps(&info->deviceid, n); 103 swaps(&info->attachment, n); 104 swaps(&info->use, n); 105 swaps(&info->num_classes, n); 106 swaps(&info->name_len, n); 107 } 108 109 if (querydata->which_device > XIAllMasterDevices) 110 g_assert(info->deviceid == querydata->which_device); 111 112 g_assert(info->deviceid >= 2); /* 0 and 1 is reserved */ 113 114 115 switch(info->deviceid) 116 { 117 case 2: /* VCP */ 118 dev = devices.vcp; 119 g_assert(info->use == XIMasterPointer); 120 g_assert(info->attachment == devices.vck->id); 121 g_assert(info->num_classes == 3); /* 2 axes + button */ 122 break; 123 case 3: /* VCK */ 124 dev = devices.vck; 125 g_assert(info->use == XIMasterKeyboard); 126 g_assert(info->attachment == devices.vcp->id); 127 g_assert(info->num_classes == 1); 128 break; 129 case 4: /* mouse */ 130 dev = devices.mouse; 131 g_assert(info->use == XISlavePointer); 132 g_assert(info->attachment == devices.vcp->id); 133 g_assert(info->num_classes == 3); /* 2 axes + button */ 134 break; 135 case 5: /* keyboard */ 136 dev = devices.kbd; 137 g_assert(info->use == XISlaveKeyboard); 138 g_assert(info->attachment == devices.vck->id); 139 g_assert(info->num_classes == 1); 140 break; 141 142 default: 143 /* We shouldn't get here */ 144 g_assert(0); 145 break; 146 } 147 g_assert(info->enabled == dev->enabled); 148 g_assert(info->name_len == strlen(dev->name)); 149 g_assert(strncmp((char*)&info[1], dev->name, info->name_len) == 0); 150 151 any = (xXIAnyInfo*)((char*)&info[1] + ((info->name_len + 3)/4) * 4); 152 for (j = 0; j < info->num_classes; j++) 153 { 154 if (client->swapped) 155 { 156 swaps(&any->type, n); 157 swaps(&any->length, n); 158 swaps(&any->sourceid, n); 159 } 160 161 switch(info->deviceid) 162 { 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, n); 173 174 g_assert(any->type == XIKeyClass); 175 g_assert(ki->num_keycodes == (xkb->max_key_code - xkb->min_key_code + 1)); 176 g_assert(any->length == (2 + ki->num_keycodes)); 177 178 kc = (uint32_t*)&ki[1]; 179 for (k = 0; k < ki->num_keycodes; k++, kc++) 180 { 181 if (client->swapped) 182 swapl(kc, n); 183 184 g_assert(*kc >= xkb->min_key_code); 185 g_assert(*kc <= xkb->max_key_code); 186 } 187 break; 188 } 189 case 2: /* VCP and mouse have the same properties */ 190 case 4: 191 { 192 g_assert(any->type == XIButtonClass || 193 any->type == XIValuatorClass); 194 195 if (any->type == XIButtonClass) 196 { 197 int len; 198 xXIButtonInfo *bi = (xXIButtonInfo*)any; 199 200 if (client->swapped) 201 swaps(&bi->num_buttons, n); 202 203 g_assert(bi->num_buttons == devices.vcp->button->numButtons); 204 205 len = 2 + bi->num_buttons + bytes_to_int32(bits_to_bytes(bi->num_buttons)); 206 g_assert(bi->length == len); 207 } else if (any->type == XIValuatorClass) 208 { 209 xXIValuatorInfo *vi = (xXIValuatorInfo*)any; 210 211 if (client->swapped) 212 { 213 swaps(&vi->number, n); 214 swapl(&vi->label, n); 215 swapl(&vi->min.integral, n); 216 swapl(&vi->min.frac, n); 217 swapl(&vi->max.integral, n); 218 swapl(&vi->max.frac, n); 219 swapl(&vi->resolution, n); 220 } 221 222 g_assert(vi->length == 11); 223 g_assert(vi->number == 0 || 224 vi->number == 1); 225 g_assert(vi->mode == XIModeRelative); 226 /* device was set up as relative, so standard 227 * values here. */ 228 g_assert(vi->min.integral == -1); 229 g_assert(vi->min.frac == 0); 230 g_assert(vi->max.integral == -1); 231 g_assert(vi->max.frac == 0); 232 g_assert(vi->resolution == 0); 233 } 234 } 235 break; 236 } 237 any = (xXIAnyInfo*)(((char*)any) + any->length * 4); 238 } 239 240 info = (xXIDeviceInfo*)any; 241 } 242} 243 244static void request_XIQueryDevice(struct test_data *querydata, 245 int deviceid, int error) 246{ 247 int rc; 248 char n; 249 ClientRec client; 250 xXIQueryDeviceReq request; 251 252 request_init(&request, XIQueryDevice); 253 client = init_client(request.length, &request); 254 reply_handler = reply_XIQueryDevice; 255 256 querydata->which_device = deviceid; 257 258 request.deviceid = deviceid; 259 rc = ProcXIQueryDevice(&client); 260 g_assert(rc == error); 261 262 if (rc != Success) 263 g_assert(client.errorValue == deviceid); 264 265 reply_handler = reply_XIQueryDevice; 266 267 client.swapped = TRUE; 268 swaps(&request.length, n); 269 swaps(&request.deviceid, n); 270 rc = SProcXIQueryDevice(&client); 271 g_assert(rc == error); 272 273 if (rc != Success) 274 g_assert(client.errorValue == deviceid); 275} 276 277static void test_XIQueryDevice(void) 278{ 279 int i; 280 xXIQueryDeviceReq request; 281 struct test_data data; 282 283 reply_handler = reply_XIQueryDevice; 284 userdata = &data; 285 request_init(&request, XIQueryDevice); 286 287 g_test_message("Testing XIAllDevices."); 288 request_XIQueryDevice(&data, XIAllDevices, Success); 289 g_test_message("Testing XIAllMasterDevices."); 290 request_XIQueryDevice(&data, XIAllMasterDevices, Success); 291 292 g_test_message("Testing existing device ids."); 293 for (i = 2; i < 6; i++) 294 request_XIQueryDevice(&data, i, Success); 295 296 g_test_message("Testing non-existing device ids."); 297 for (i = 6; i <= 0xFFFF; i++) 298 request_XIQueryDevice(&data, i, BadDevice); 299 300 301 reply_handler = NULL; 302 303} 304 305int main(int argc, char** argv) 306{ 307 g_test_init(&argc, &argv,NULL); 308 g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); 309 310 init_simple(); 311 312 g_test_add_func("/dix/xi2protocol/XIQueryDevice", test_XIQueryDevice); 313 314 return g_test_run(); 315} 316 317