Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / unit / test-uhid.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2014  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdbool.h>
31 #include <inttypes.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <sys/socket.h>
35
36 #include <glib.h>
37
38 #include "src/shared/uhid.h"
39 #include "src/shared/util.h"
40
41 #include "src/shared/tester.h"
42
43 struct test_pdu {
44         bool valid;
45         const uint8_t *data;
46         size_t size;
47 };
48
49 struct test_data {
50         char *test_name;
51         struct test_pdu *pdu_list;
52 };
53
54 struct context {
55         struct bt_uhid *uhid;
56         guint source;
57         guint process;
58         int fd;
59         unsigned int pdu_offset;
60         const struct test_data *data;
61 };
62
63 #define event(args...)                                          \
64         {                                                       \
65                 .valid = true,                                  \
66                 .data = (void *) args,                          \
67                 .size = sizeof(*args),                          \
68         }
69
70 #define define_test(name, function, args...)                            \
71         do {                                                            \
72                 const struct test_pdu pdus[] = {                        \
73                         args, { }                                       \
74                 };                                                      \
75                 static struct test_data data;                           \
76                 data.test_name = g_strdup(name);                        \
77                 data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
78                 tester_add(name, &data, NULL, function, NULL);          \
79         } while (0)
80
81 static void test_debug(const char *str, void *user_data)
82 {
83         const char *prefix = user_data;
84
85         tester_debug("%s%s\n", prefix, str);
86 }
87
88 static void test_free(gconstpointer user_data)
89 {
90         const struct test_data *data = user_data;
91
92         g_free(data->test_name);
93         g_free(data->pdu_list);
94 }
95
96 static void destroy_context(struct context *context)
97 {
98         if (context->source > 0)
99                 g_source_remove(context->source);
100
101         bt_uhid_unref(context->uhid);
102
103         test_free(context->data);
104         g_free(context);
105 }
106
107 static gboolean context_quit(gpointer user_data)
108 {
109         struct context *context = user_data;
110
111         if (context == NULL)
112                 return FALSE;
113
114         if (context->process > 0)
115                 g_source_remove(context->process);
116
117         destroy_context(context);
118         tester_test_passed();
119
120         return FALSE;
121 }
122
123 static gboolean send_pdu(gpointer user_data)
124 {
125         struct context *context = user_data;
126         const struct test_pdu *pdu;
127         ssize_t len;
128
129         pdu = &context->data->pdu_list[context->pdu_offset++];
130
131         len = write(context->fd, pdu->data, pdu->size);
132
133
134         util_hexdump('<', pdu->data, len, test_debug, "uHID: ");
135
136         g_assert_cmpint(len, ==, pdu->size);
137
138         context->process = 0;
139         return FALSE;
140 }
141
142 static void context_process(struct context *context)
143 {
144         if (!context->data->pdu_list[context->pdu_offset].valid) {
145                 context_quit(context);
146                 return;
147         }
148
149         context->process = g_idle_add(send_pdu, context);
150 }
151
152 static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
153                                                         gpointer user_data)
154 {
155         struct context *context = user_data;
156         const struct test_pdu *pdu;
157         unsigned char buf[sizeof(struct uhid_event)];
158         ssize_t len;
159         int fd;
160
161         pdu = &context->data->pdu_list[context->pdu_offset++];
162
163         if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
164                 context->source = 0;
165                 g_print("%s: cond %x\n", __func__, cond);
166                 return FALSE;
167         }
168
169         fd = g_io_channel_unix_get_fd(channel);
170
171         len = read(fd, buf, sizeof(buf));
172
173         g_assert(len > 0);
174
175         util_hexdump('>', buf, len, test_debug, "uHID: ");
176
177         g_assert_cmpint(len, ==, pdu->size);
178
179         g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
180
181         context_process(context);
182
183         return TRUE;
184 }
185
186 static struct context *create_context(gconstpointer data)
187 {
188         struct context *context = g_new0(struct context, 1);
189         GIOChannel *channel;
190         int err, sv[2];
191
192         err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
193         g_assert(err == 0);
194
195         context->uhid = bt_uhid_new(sv[0]);
196         g_assert(context->uhid != NULL);
197
198         channel = g_io_channel_unix_new(sv[1]);
199
200         g_io_channel_set_close_on_unref(channel, TRUE);
201         g_io_channel_set_encoding(channel, NULL, NULL);
202         g_io_channel_set_buffered(channel, FALSE);
203
204         context->source = g_io_add_watch(channel,
205                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
206                                 test_handler, context);
207         g_assert(context->source > 0);
208
209         g_io_channel_unref(channel);
210
211         context->fd = sv[1];
212         context->data = data;
213
214         return context;
215 }
216
217 static const struct uhid_event ev_create = {
218         .type = UHID_CREATE,
219 };
220
221 static const struct uhid_event ev_destroy = {
222         .type = UHID_DESTROY,
223 };
224
225 static const struct uhid_event ev_feature_answer = {
226         .type = UHID_FEATURE_ANSWER,
227 };
228
229 static const struct uhid_event ev_input = {
230         .type = UHID_INPUT,
231 };
232
233 static const struct uhid_event ev_output = {
234         .type = UHID_OUTPUT,
235 };
236
237 static const struct uhid_event ev_feature = {
238         .type = UHID_FEATURE,
239 };
240
241 static void test_client(gconstpointer data)
242 {
243         struct context *context = create_context(data);
244
245         if (g_str_equal(context->data->test_name, "/uhid/command/create"))
246                 bt_uhid_send(context->uhid, &ev_create);
247
248         if (g_str_equal(context->data->test_name, "/uhid/command/destroy"))
249                 bt_uhid_send(context->uhid, &ev_destroy);
250
251         if (g_str_equal(context->data->test_name,
252                                                 "/uhid/command/feature_answer"))
253                 bt_uhid_send(context->uhid, &ev_feature_answer);
254
255         if (g_str_equal(context->data->test_name, "/uhid/command/input"))
256                 bt_uhid_send(context->uhid, &ev_input);
257
258         context_quit(context);
259 }
260
261 static void handle_output(struct uhid_event *ev, void *user_data)
262 {
263         g_assert_cmpint(ev->type, ==, UHID_OUTPUT);
264
265         context_quit(user_data);
266 }
267
268 static void handle_feature(struct uhid_event *ev, void *user_data)
269 {
270         g_assert_cmpint(ev->type, ==, UHID_FEATURE);
271
272         context_quit(user_data);
273 }
274
275 static void test_server(gconstpointer data)
276 {
277         struct context *context = create_context(data);
278
279         bt_uhid_register(context->uhid, UHID_OUTPUT, handle_output, context);
280         bt_uhid_register(context->uhid, UHID_FEATURE, handle_feature, context);
281
282         g_idle_add(send_pdu, context);
283 }
284
285 int main(int argc, char *argv[])
286 {
287         tester_init(&argc, &argv);
288
289         define_test("/uhid/command/create", test_client, event(&ev_create));
290         define_test("/uhid/command/destroy", test_client, event(&ev_destroy));
291         define_test("/uhid/command/feature_answer", test_client,
292                                                 event(&ev_feature_answer));
293         define_test("/uhid/command/input", test_client, event(&ev_input));
294
295         define_test("/uhid/event/output", test_server, event(&ev_output));
296         define_test("/uhid/event/feature", test_server, event(&ev_feature));
297
298         return tester_run();
299 }