1/**
2 * Copyright © 2011 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 <X11/Xlib.h>
32#include <list.h>
33#include <string.h>
34#include <assert.h>
35#include <stdlib.h>
36
37#include "tests-common.h"
38
39struct parent {
40    int a;
41    struct xorg_list children;
42    int b;
43};
44
45struct child {
46    int foo;
47    int bar;
48    struct xorg_list node;
49};
50
51static void
52test_xorg_list_init(void)
53{
54    struct parent parent, tmp;
55
56    memset(&parent, 0, sizeof(parent));
57    parent.a = 0xa5a5a5;
58    parent.b = ~0xa5a5a5;
59
60    tmp = parent;
61
62    xorg_list_init(&parent.children);
63
64    /* test we haven't touched anything else. */
65    assert(parent.a == tmp.a);
66    assert(parent.b == tmp.b);
67
68    assert(xorg_list_is_empty(&parent.children));
69}
70
71static void
72test_xorg_list_add(void)
73{
74    struct parent parent = { 0 };
75    struct child child[3];
76    struct child *c;
77
78    xorg_list_init(&parent.children);
79
80    xorg_list_add(&child[0].node, &parent.children);
81    assert(!xorg_list_is_empty(&parent.children));
82
83    c = xorg_list_first_entry(&parent.children, struct child, node);
84
85    assert(memcmp(c, &child[0], sizeof(struct child)) == 0);
86
87    /* note: xorg_list_add prepends */
88    xorg_list_add(&child[1].node, &parent.children);
89    c = xorg_list_first_entry(&parent.children, struct child, node);
90
91    assert(memcmp(c, &child[1], sizeof(struct child)) == 0);
92
93    xorg_list_add(&child[2].node, &parent.children);
94    c = xorg_list_first_entry(&parent.children, struct child, node);
95
96    assert(memcmp(c, &child[2], sizeof(struct child)) == 0);
97};
98
99static void
100test_xorg_list_append(void)
101{
102    struct parent parent = { 0 };
103    struct child child[3];
104    struct child *c;
105    int i;
106
107    xorg_list_init(&parent.children);
108
109    xorg_list_append(&child[0].node, &parent.children);
110    assert(!xorg_list_is_empty(&parent.children));
111
112    c = xorg_list_first_entry(&parent.children, struct child, node);
113
114    assert(memcmp(c, &child[0], sizeof(struct child)) == 0);
115    c = xorg_list_last_entry(&parent.children, struct child, node);
116
117    assert(memcmp(c, &child[0], sizeof(struct child)) == 0);
118
119    xorg_list_append(&child[1].node, &parent.children);
120    c = xorg_list_first_entry(&parent.children, struct child, node);
121
122    assert(memcmp(c, &child[0], sizeof(struct child)) == 0);
123    c = xorg_list_last_entry(&parent.children, struct child, node);
124
125    assert(memcmp(c, &child[1], sizeof(struct child)) == 0);
126
127    xorg_list_append(&child[2].node, &parent.children);
128    c = xorg_list_first_entry(&parent.children, struct child, node);
129
130    assert(memcmp(c, &child[0], sizeof(struct child)) == 0);
131    c = xorg_list_last_entry(&parent.children, struct child, node);
132
133    assert(memcmp(c, &child[2], sizeof(struct child)) == 0);
134
135    i = 0;
136    xorg_list_for_each_entry(c, &parent.children, node) {
137        assert(memcmp(c, &child[i++], sizeof(struct child)) == 0);
138    }
139};
140
141static void
142test_xorg_list_del(void)
143{
144    struct parent parent = { 0 };
145    struct child child[2];
146    struct child *c;
147
148    xorg_list_init(&parent.children);
149
150    xorg_list_add(&child[0].node, &parent.children);
151    assert(!xorg_list_is_empty(&parent.children));
152
153    xorg_list_del(&parent.children);
154    assert(xorg_list_is_empty(&parent.children));
155
156    xorg_list_add(&child[0].node, &parent.children);
157    xorg_list_del(&child[0].node);
158    assert(xorg_list_is_empty(&parent.children));
159
160    xorg_list_add(&child[0].node, &parent.children);
161    xorg_list_add(&child[1].node, &parent.children);
162
163    c = xorg_list_first_entry(&parent.children, struct child, node);
164
165    assert(memcmp(c, &child[1], sizeof(struct child)) == 0);
166
167    /* delete first node */
168    xorg_list_del(&child[1].node);
169    assert(!xorg_list_is_empty(&parent.children));
170    assert(xorg_list_is_empty(&child[1].node));
171    c = xorg_list_first_entry(&parent.children, struct child, node);
172
173    assert(memcmp(c, &child[0], sizeof(struct child)) == 0);
174
175    /* delete last node */
176    xorg_list_add(&child[1].node, &parent.children);
177    xorg_list_del(&child[0].node);
178    c = xorg_list_first_entry(&parent.children, struct child, node);
179
180    assert(memcmp(c, &child[1], sizeof(struct child)) == 0);
181
182    /* delete list head */
183    xorg_list_add(&child[0].node, &parent.children);
184    xorg_list_del(&parent.children);
185    assert(xorg_list_is_empty(&parent.children));
186    assert(!xorg_list_is_empty(&child[0].node));
187    assert(!xorg_list_is_empty(&child[1].node));
188}
189
190static void
191test_xorg_list_for_each(void)
192{
193    struct parent parent = { 0 };
194    struct child child[3];
195    struct child *c;
196    int i = 0;
197
198    xorg_list_init(&parent.children);
199
200    xorg_list_add(&child[2].node, &parent.children);
201    xorg_list_add(&child[1].node, &parent.children);
202    xorg_list_add(&child[0].node, &parent.children);
203
204    xorg_list_for_each_entry(c, &parent.children, node) {
205        assert(memcmp(c, &child[i], sizeof(struct child)) == 0);
206        i++;
207    }
208
209    /* foreach on empty list */
210    xorg_list_del(&parent.children);
211    assert(xorg_list_is_empty(&parent.children));
212
213    xorg_list_for_each_entry(c, &parent.children, node) {
214        assert(0);              /* we must not get here */
215    }
216}
217
218struct foo {
219    char a;
220    struct foo *next;
221    char b;
222};
223
224static void
225test_nt_list_init(void)
226{
227    struct foo foo;
228
229    foo.a = 10;
230    foo.b = 20;
231    nt_list_init(&foo, next);
232
233    assert(foo.a == 10);
234    assert(foo.b == 20);
235    assert(foo.next == NULL);
236    assert(nt_list_next(&foo, next) == NULL);
237}
238
239static void
240test_nt_list_append(void)
241{
242    int i;
243    struct foo *foo = calloc(10, sizeof(struct foo));
244    struct foo *item;
245
246    for (item = foo, i = 1; i <= 10; i++, item++) {
247        item->a = i;
248        item->b = i * 2;
249        nt_list_init(item, next);
250
251        if (item != foo)
252            nt_list_append(item, foo, struct foo, next);
253    }
254
255    /* Test using nt_list_next */
256    for (item = foo, i = 1; i <= 10; i++, item = nt_list_next(item, next)) {
257        assert(item->a == i);
258        assert(item->b == i * 2);
259    }
260
261    /* Test using nt_list_for_each_entry */
262    i = 1;
263    nt_list_for_each_entry(item, foo, next) {
264        assert(item->a == i);
265        assert(item->b == i * 2);
266        i++;
267    }
268    assert(i == 11);
269}
270
271static void
272test_nt_list_insert(void)
273{
274    int i;
275    struct foo *foo = calloc(10, sizeof(struct foo));
276    struct foo *item;
277
278    foo->a = 1;
279    foo->b = 2;
280    nt_list_init(foo, next);
281
282    for (item = &foo[1], i = 10; i > 1; i--, item++) {
283        item->a = i;
284        item->b = i * 2;
285        nt_list_init(item, next);
286        nt_list_insert(item, foo, struct foo, next);
287    }
288
289    /* Test using nt_list_next */
290    for (item = foo, i = 1; i <= 10; i++, item = nt_list_next(item, next)) {
291        assert(item->a == i);
292        assert(item->b == i * 2);
293    }
294
295    /* Test using nt_list_for_each_entry */
296    i = 1;
297    nt_list_for_each_entry(item, foo, next) {
298        assert(item->a == i);
299        assert(item->b == i * 2);
300        i++;
301    }
302    assert(i == 11);
303}
304
305static void
306test_nt_list_delete(void)
307{
308    int i = 1;
309    struct foo *list = calloc(10, sizeof(struct foo));
310    struct foo *foo = list;
311    struct foo *item, *tmp;
312    struct foo *empty_list = foo;
313
314    nt_list_init(empty_list, next);
315    nt_list_del(empty_list, empty_list, struct foo, next);
316
317    assert(!empty_list);
318
319    for (item = foo, i = 1; i <= 10; i++, item++) {
320        item->a = i;
321        item->b = i * 2;
322        nt_list_init(item, next);
323
324        if (item != foo)
325            nt_list_append(item, foo, struct foo, next);
326    }
327
328    i = 0;
329    nt_list_for_each_entry(item, foo, next) {
330        i++;
331    }
332    assert(i == 10);
333
334    /* delete last item */
335    nt_list_del(&foo[9], foo, struct foo, next);
336
337    i = 0;
338    nt_list_for_each_entry(item, foo, next) {
339        assert(item->a != 10);  /* element 10 is gone now */
340        i++;
341    }
342    assert(i == 9);             /* 9 elements left */
343
344    /* delete second item */
345    nt_list_del(foo->next, foo, struct foo, next);
346
347    assert(foo->next->a == 3);
348
349    i = 0;
350    nt_list_for_each_entry(item, foo, next) {
351        assert(item->a != 10);  /* element 10 is gone now */
352        assert(item->a != 2);   /* element 2 is gone now */
353        i++;
354    }
355    assert(i == 8);             /* 9 elements left */
356
357    item = foo;
358    /* delete first item */
359    nt_list_del(foo, foo, struct foo, next);
360
361    assert(item != foo);
362    assert(item->next == NULL);
363    assert(foo->a == 3);
364    assert(foo->next->a == 4);
365
366    nt_list_for_each_entry_safe(item, tmp, foo, next) {
367        nt_list_del(item, foo, struct foo, next);
368    }
369
370    assert(!foo);
371    assert(!item);
372
373    free(list);
374}
375
376int
377list_test(void)
378{
379    test_xorg_list_init();
380    test_xorg_list_add();
381    test_xorg_list_append();
382    test_xorg_list_del();
383    test_xorg_list_for_each();
384
385    test_nt_list_init();
386    test_nt_list_append();
387    test_nt_list_insert();
388    test_nt_list_delete();
389
390    return 0;
391}
392