source: tags/arb-6.0/SL/CB/cb.cxx

Last change on this file was 11513, checked in by westram, 11 years ago
File size: 17.1 KB
Line 
1// ============================================================== //
2//                                                                //
3//   File      : cb.cxx                                           //
4//   Purpose   : currently only a test sandbox                    //
5//                                                                //
6//   Coded by Ralf Westram (coder@reallysoft.de) in August 2011   //
7//   Institute of Microbiology (Technical University Munich)      //
8//   http://www.arb-home.de/                                      //
9//                                                                //
10// ============================================================== //
11
12#include <cb.h>
13#include <string>
14#include <stdint.h>
15
16using namespace std;
17
18STATIC_ASSERT(sizeof(int*) == sizeof(AW_CL)); // important for casted db-callback type (GB_CB vs GB_CB_wanted..)
19
20// --------------------------------------------------------------------------------
21
22#ifdef UNIT_TESTS
23#include <test_unit.h>
24
25// ---------------------------------------------
26//      compile time test of type inspection
27
28#define COMPILE_ASSERT_POINTER_TO(ISTYPE,POINTER)               \
29    STATIC_ASSERT(TypeT<POINTER>::IsPtrT &&                     \
30                  TypeT<CompountT<POINTER>::BaseT>::ISTYPE)
31
32typedef int (*somefun)(const char *);
33int myfun(const char *) { return 0; }
34static somefun sfun = myfun;
35
36enum someenum { A, B };
37
38class someclass { public : int memfun() { return -1; } };
39
40
41STATIC_ASSERT(IsFundaT<void>::No);
42STATIC_ASSERT(IsFundaT<bool>::Yes);
43STATIC_ASSERT(IsFundaT<int>::Yes);
44STATIC_ASSERT(IsFundaT<long>::Yes);
45STATIC_ASSERT(IsFundaT<double>::Yes);
46
47STATIC_ASSERT(IsFundaT<int*>::No);
48COMPILE_ASSERT_POINTER_TO(IsFundaT, int*);
49COMPILE_ASSERT_POINTER_TO(IsPtrT, int**);
50STATIC_ASSERT(IsFundaT<int&>::No);
51
52STATIC_ASSERT(IsFundaT<somefun>::No);
53STATIC_ASSERT(IsFundaT<typeof(myfun)>::No);
54STATIC_ASSERT(IsFundaT<someenum>::No);
55
56STATIC_ASSERT(IsFunctionT<typeof(myfun)>::Yes);
57
58STATIC_ASSERT(IsFunctionT<somefun>::No); // somefun is pointer to functiontype
59COMPILE_ASSERT_POINTER_TO(IsFuncT, somefun);
60STATIC_ASSERT(IsFunctionT<typeof(sfun)>::No); // sfun is pointer to functiontype
61COMPILE_ASSERT_POINTER_TO(IsFuncT, typeof(sfun));
62STATIC_ASSERT(IsFunctionT<void>::No);
63STATIC_ASSERT(IsFunctionT<int>::No);
64STATIC_ASSERT(IsFunctionT<bool>::No);
65
66STATIC_ASSERT(CompountT<const int&>::IsRefT);
67STATIC_ASSERT(CompountT<int&>::IsRefT);
68
69STATIC_ASSERT(IsEnumT<someenum>::Yes);
70COMPILE_ASSERT_POINTER_TO(IsEnumT, someenum*);
71
72STATIC_ASSERT(IsEnumT<int>::No);
73STATIC_ASSERT(IsEnumT<int*>::No);
74STATIC_ASSERT(IsEnumT<int&>::No);
75STATIC_ASSERT(IsEnumT<somefun>::No);
76STATIC_ASSERT(IsEnumT<typeof(myfun)>::No);
77
78STATIC_ASSERT(IsClassT<someclass>::Yes);
79COMPILE_ASSERT_POINTER_TO(IsClassT, someclass*);
80
81STATIC_ASSERT(IsClassT<int>::No);
82STATIC_ASSERT(IsClassT<int*>::No);
83STATIC_ASSERT(IsClassT<int&>::No);
84STATIC_ASSERT(IsClassT<someenum>::No);
85STATIC_ASSERT(IsClassT<somefun>::No);
86STATIC_ASSERT(IsClassT<typeof(myfun)>::No);
87
88STATIC_ASSERT(TypeT<int>::IsFundaT);
89STATIC_ASSERT(TypeT<int*>::IsPtrT);
90STATIC_ASSERT(TypeT<int&>::IsRefT);
91STATIC_ASSERT(TypeT<int[]>::IsArrayT);
92STATIC_ASSERT(TypeT<int[7]>::IsArrayT);
93STATIC_ASSERT(TypeT<typeof(myfun)>::IsFuncT);
94STATIC_ASSERT(TypeT<typeof(&someclass::memfun)>::IsPtrMemT);
95STATIC_ASSERT(TypeT<someenum>::IsEnumT);
96STATIC_ASSERT(TypeT<someclass>::IsClassT);
97
98// -----------------------
99//      test callbacks
100
101#define TRACE
102
103static uint32_t traceChecksum;
104const int            BUFFERSIZE = 100;
105char                 traceBuffer[BUFFERSIZE];
106
107__ATTR__FORMAT(1) static void tracef(const char *format, ...) {
108    va_list parg;
109    va_start(parg, format);
110    int printed = vsnprintf(traceBuffer, BUFFERSIZE, format, parg);
111    va_end(parg);
112
113#if defined(TRACE)
114    fputs(traceBuffer, stdout);
115#endif
116    if (printed >= BUFFERSIZE) {
117        printf("\nprinted=%i\n", printed);
118    }
119    TEST_EXPECT(printed<BUFFERSIZE);
120
121    traceChecksum = 0;
122    for (int p = 0; p<printed; ++p) {
123        traceChecksum = (traceChecksum<<1)^(traceChecksum>>31)^traceBuffer[p];
124    }
125}
126
127static AW_root    *fake_root   = (AW_root*)1;
128static AW_window  *fake_win    = (AW_window*)2;
129static GBDATA     *fake_gbd    = (GBDATA*)3;
130static AW_awar    *fake_awar   = (AW_awar*)4;
131static bool        fake_bool   = false;
132static GB_CB_TYPE  fake_gbtype = GB_CB_CHANGED;
133
134static void rcb0(AW_root *r) {
135    TEST_EXPECT(r == fake_root);
136    tracef("rcb0()\n");
137}
138static void rcb1(AW_root *r, const char *name) {
139    TEST_EXPECT(r == fake_root);
140    tracef("rcb1(%s)\n", name);
141}
142static void rcb2(AW_root *r, const char *name, int val) {
143    TEST_EXPECT(r == fake_root);
144    tracef("rcb2(%s=%i) [int]\n", name, val);
145}
146static void rcb2(AW_root *r, const char *name, long val) {
147    TEST_EXPECT(r == fake_root);
148    tracef("rcb2(%s=%li) [long]\n", name, val);
149}
150
151static void wcb0(AW_window *w) {
152    TEST_EXPECT(w == fake_win);
153    tracef("wcb0()\n");
154}
155static void wcb1(AW_window *w, const char *name) {
156    TEST_EXPECT(w == fake_win);
157    tracef("wcb1(%s)\n", name);
158}
159static void wcb1(AW_window *w, string *name) {
160    TEST_EXPECT(w == fake_win);
161    tracef("wcb1(%s) [string]\n", name->c_str());
162}
163static void wcb2(AW_window *w, const char *name, const char *val) {
164    TEST_EXPECT(w == fake_win);
165    tracef("wcb2(%s=%s) [const char/const char]\n", name, val);
166}
167static void wcb2(AW_window *w, const string *name, const string *val) {
168    TEST_EXPECT(w == fake_win);
169    tracef("wcb2(%s=%s) [string/string]\n", name->c_str(), val->c_str());
170}
171static void wcb2(AW_window *w, const char *name, int val) {
172    TEST_EXPECT(w == fake_win);
173    tracef("wcb2(%s=%i) [int]\n", name, val);
174}
175static void wcb2(AW_window *w, const char *name, long val) {
176    TEST_EXPECT(w == fake_win);
177    tracef("wcb2(%s=%li) [long]\n", name, val);
178}
179static void wcb2(AW_window *w, char c, long long val) {
180    TEST_EXPECT(w == fake_win);
181    tracef("wcb2(%c=%lli) [long long]\n", c, val);
182}
183
184static void tacb0(AW_awar *a) {
185    TEST_EXPECT(a == fake_awar);
186    tracef("tacb0()\n");
187}
188static void tacb1(AW_awar *a, bool b) {
189    TEST_EXPECT(a == fake_awar);
190    TEST_EXPECT(b == fake_bool);
191    tracef("tacb1()\n");
192}
193static void tacb2(AW_awar *a, bool b, const char *name) {
194    TEST_EXPECT(a == fake_awar);
195    TEST_EXPECT(b == fake_bool);
196    tracef("tacb2(%s)\n", name);
197}
198static void tacb2(AW_awar *a, bool b, int val) {
199    TEST_EXPECT(a == fake_awar);
200    TEST_EXPECT(b == fake_bool);
201    tracef("tacb2(%i)\n", val);
202}
203
204static void ucb0(UNFIXED) {
205    tracef("ucb0()\n");
206}
207static void ucb1(UNFIXED, const char *name) {
208    tracef("ucb1(%s)\n", name);
209}
210static void ucb2(UNFIXED, const char *name, int val) {
211    tracef("ucb2(%s=%i) [int]\n", name, val);
212}
213static void ucb2(UNFIXED, const char *name, long val) {
214    tracef("ucb2(%s=%li) [long]\n", name, val);
215}
216
217static AW_window *cwcb0(AW_root *r) {
218    TEST_EXPECT(r == fake_root);
219    tracef("cwcb0()\n");
220    return fake_win;
221}
222static AW_window *cwcb1(AW_root *r, int x) {
223    TEST_EXPECT(r == fake_root);
224    tracef("cwcb1(%i)\n", x);
225    return fake_win;
226}
227static AW_window *cwcb1(AW_root *r, const long *lp) {
228    TEST_EXPECT(r == fake_root);
229    tracef("cwcb1(%li) [long ptr]\n", *lp);
230    return fake_win;
231}
232static AW_window *cwcb1(AW_root *r, const int *x) {
233    TEST_EXPECT(r == fake_root);
234    tracef("cwcb1(%i) [const ptr]\n", *x);
235    return fake_win;
236}
237static AW_window *cwcb1(AW_root *r, int *x) {
238    TEST_EXPECT(r == fake_root);
239    tracef("cwcb1(%i) [mutable ptr]\n", *x);
240    *x *= 2; // modify callback argument!
241    return fake_win;
242}
243static AW_window *cwcb1(AW_root *r, char* s) {
244    TEST_EXPECT(r == fake_root);
245    tracef("cwcb1(%s) [mutable]\n", s);
246    return fake_win;
247}
248static AW_window *cwcb1(AW_root *r, const char* s) {
249    TEST_EXPECT(r == fake_root);
250    tracef("cwcb1(%s) [const]\n", s);
251    return fake_win;
252}
253static AW_window *cwcb2(AW_root *r, const char *s1, const char *s2) {
254    TEST_EXPECT(r == fake_root);
255    tracef("cwcb2(%s,%s) [const const]\n", s1, s2);
256    return fake_win;
257}
258static AW_window *cwcb2(AW_root *r, const char *s1, char *s2) {
259    TEST_EXPECT(r == fake_root);
260    tracef("cwcb2(%s,%s) [const mutable]\n", s1, s2);
261    return fake_win;
262}
263
264static AW_window *cwcb3(AW_root *r, const char *s1, const char *s2) {
265    TEST_EXPECT(r == fake_root);
266    tracef("cwcb3(%s,%s) [const const]\n", s1, s2);
267    return fake_win;
268}
269static AW_window *cwcb3(AW_root *r, const char *s1, char *s2) {
270    TEST_EXPECT(r == fake_root);
271    tracef("cwcb3(%s,%s) [const mutable]\n", s1, s2);
272    return fake_win;
273}
274static AW_window *cwcb3(AW_root *r, char *s1, const char *s2) {
275    TEST_EXPECT(r == fake_root);
276    tracef("cwcb3(%s,%s) [mutable const]\n", s1, s2);
277    return fake_win;
278}
279static AW_window *cwcb3(AW_root *r, char *s1, char *s2) {
280    TEST_EXPECT(r == fake_root);
281    tracef("cwcb3(%s,%s) [mutable mutable]\n", s1, s2);
282    return fake_win;
283}
284
285static void dbcb01(GBDATA *gbd) {
286    TEST_EXPECT(gbd == fake_gbd);
287    tracef("dbcb01()\n");
288}
289static void dbcb012(GBDATA *gbd, GB_CB_TYPE t) {
290    TEST_EXPECT(gbd == fake_gbd && t == fake_gbtype);
291    tracef("dbcb012()\n");
292}
293static void dbcb02(GB_CB_TYPE t) {
294    tracef("dbcb02(%i)\n", int(t));
295}
296static void dbcb1(GBDATA *gbd, int x, GB_CB_TYPE t) {
297    TEST_EXPECT(gbd == fake_gbd && t == fake_gbtype);
298    tracef("dbcb1(%i) [int]\n", x);
299}
300static void dbcb1(GBDATA *gbd, const char *n, GB_CB_TYPE t) {
301    TEST_EXPECT(gbd == fake_gbd && t == fake_gbtype);
302    tracef("dbcb1(%s) [const char]\n", n);
303}
304
305static void plaincb() {
306    tracef("plaincb()\n");
307}
308static AW_window *cwcb_plain() {
309    tracef("cwcb_plain()\n");
310    return fake_win;
311}
312
313inline void call(const RootCallback& rcb) { rcb(fake_root); }
314inline void call(const WindowCallback& wcb) { wcb(fake_win); }
315inline void call(const CreateWindowCallback& cwcb) { TEST_EXPECT(cwcb(fake_root) == fake_win); }
316inline void call(const DatabaseCallback& dbcb) { dbcb(fake_gbd, fake_gbtype); }
317inline void call(const TreeAwarCallback& tacb) { tacb(fake_awar, fake_bool); }
318
319#define TEST_CB(cb,expectedChecksum) do {                               \
320        traceChecksum = -666;                                           \
321        call(cb);                                                       \
322        TEST_EXPECT_EQUAL(traceChecksum, (uint32_t)expectedChecksum);   \
323    } while(0)
324
325#define TEST_CB_TRACE(cb,expectedOutput) do {           \
326        call(cb);                                       \
327        TEST_EXPECT_EQUAL(traceBuffer, expectedOutput); \
328    } while(0)
329
330#define TEST_CB_TRACE__BROKEN(cb,expectedOutput) do {           \
331        call(cb);                                               \
332        TEST_EXPECT_EQUAL__BROKEN(traceBuffer, expectedOutput); \
333    } while(0)
334
335
336static void freeCharp(char *str) { free(str); }
337static void freeCharp(char *str1, char *str2) { free(str1); free(str2); }
338static void deleteString(string *str) { delete str; }
339static void deleteString(string *str1, string *str2) { delete str1; delete str2; }
340
341void TEST_cbs() {
342    // MISSING_TEST("please log");
343    // for (int i = 0; i<100000; ++i)
344    {
345        TEST_CB_TRACE(makeRootCallback(plaincb),             "plaincb()\n");
346        TEST_CB_TRACE(makeRootCallback(rcb0),                "rcb0()\n");
347        TEST_CB_TRACE(makeRootCallback(rcb1,  "dispatched"), "rcb1(dispatched)\n");
348        TEST_CB_TRACE(makeRootCallback(rcb2, "age",  46),    "rcb2(age=46) [int]\n");
349        TEST_CB_TRACE(makeRootCallback(rcb2, "size", 178L),  "rcb2(size=178) [long]\n");
350
351        TEST_CB_TRACE(makeWindowCallback(plaincb),            "plaincb()\n");
352        TEST_CB_TRACE(makeWindowCallback(wcb0),               "wcb0()\n");
353        TEST_CB_TRACE(makeWindowCallback(wcb1, "dispatched"), "wcb1(dispatched)\n");
354        TEST_CB_TRACE(makeWindowCallback(wcb2, "age",  46),   "wcb2(age=46) [int]\n");
355        TEST_CB_TRACE(makeWindowCallback(wcb2, "size", 178L), "wcb2(size=178) [long]\n");
356
357        TEST_CB_TRACE(makeTreeAwarCallback(plaincb),             "plaincb()\n");
358        TEST_CB_TRACE(makeTreeAwarCallback(tacb0),               "tacb0()\n");
359        TEST_CB_TRACE(makeTreeAwarCallback(tacb1),               "tacb1()\n");
360        TEST_CB_TRACE(makeTreeAwarCallback(tacb2, "dispatched"), "tacb2(dispatched)\n");
361        TEST_CB_TRACE(makeTreeAwarCallback(tacb2, 46),           "tacb2(46)\n");
362
363        // declaring a cb with UNFIXED as fixed-argument allows to use callbacks as RootCallback AND as WindowCallback
364        // (when we use sigc++ in the future this should be changed to allowing functions w/o the UNFIXED-parameter)
365
366        TEST_CB_TRACE(makeRootCallback(ucb0),                "ucb0()\n");
367        TEST_CB_TRACE(makeRootCallback(ucb1,  "dispatched"), "ucb1(dispatched)\n");
368        TEST_CB_TRACE(makeRootCallback(ucb2, "age",  46),    "ucb2(age=46) [int]\n");
369        TEST_CB_TRACE(makeRootCallback(ucb2, "size", 178L),  "ucb2(size=178) [long]\n");
370
371        TEST_CB_TRACE(makeWindowCallback(ucb0),                "ucb0()\n");
372        TEST_CB_TRACE(makeWindowCallback(ucb1,  "dispatched"), "ucb1(dispatched)\n");
373        TEST_CB_TRACE(makeWindowCallback(ucb2, "age",  46),    "ucb2(age=46) [int]\n");
374        TEST_CB_TRACE(makeWindowCallback(ucb2, "size", 178L),  "ucb2(size=178) [long]\n");
375
376#if defined(ARB_64)
377        TEST_CB_TRACE(makeWindowCallback(wcb2, 'l', 49710827735915452LL),  "wcb2(l=49710827735915452) [long long]\n");
378#endif
379
380        TEST_CB_TRACE(makeCreateWindowCallback(cwcb_plain), "cwcb_plain()\n");
381        TEST_CB_TRACE(makeCreateWindowCallback(cwcb0),      "cwcb0()\n");
382        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, 77),  "cwcb1(77)\n");
383
384        // TEST_CB(makeDatabaseCallback(plaincb), 44760); // does not work (ambiguous due to 2 fixed arguments of DatabaseCallback)
385        TEST_CB_TRACE(makeDatabaseCallback(dbcb01),    "dbcb01()\n");
386        TEST_CB_TRACE(makeDatabaseCallback(dbcb012),   "dbcb012()\n");
387        TEST_CB_TRACE(makeDatabaseCallback(dbcb02),    "dbcb02(2)\n"); // call dbcb02 with fixed argument (i.e. with argument normally passed by ARBDB)
388        TEST_CB_TRACE(makeDatabaseCallback(dbcb1, 77), "dbcb1(77) [int]\n");
389
390        TEST_CB_TRACE(makeDatabaseCallback(dbcb1, freeCharp, strdup("test")), "dbcb1(test) [const char]\n");
391
392        // callbacks with deallocator
393
394        // TEST_CB(makeWindowCallback(wcb1, strdup("leak")), 0x163ac); // leaks
395        TEST_CB_TRACE(makeWindowCallback(wcb1, freeCharp, strdup("leak")), "wcb1(leak)\n");
396        // TEST_CB(makeWindowCallback(wcb1, freeCharp, "leak"), 0x163ac); // does not compile (can't call freeCharp with const char *)
397        TEST_CB_TRACE(makeWindowCallback(wcb1, deleteString, new string("leak")), "wcb1(leak) [string]\n");
398        // TEST_CB(makeWindowCallback(wcb2, strdup("hue"), strdup("hott")), 0xe09d7b1); // leaks
399        TEST_CB_TRACE(makeWindowCallback(wcb2, freeCharp, strdup("hue"), strdup("hott")), "wcb2(hue=hott) [const char/const char]\n");
400        TEST_CB_TRACE(makeWindowCallback(wcb2, deleteString, new string("hue"), new string("hott")), "wcb2(hue=hott) [string/string]\n");
401
402        // test const vs non-const pointers:
403        char       *mut = strdup("mut");
404        const char *con = "con";
405
406        // if only const/const and const/mutable exists -> shall always select as much mutable as possible
407        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, con, con), "cwcb2(con,con) [const const]\n");   // exact match
408        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, mut, con), "cwcb2(mut,con) [const const]\n");   // fallback to const/const
409        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, con, mut), "cwcb2(con,mut) [const mutable]\n"); // exact match
410        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, mut, mut), "cwcb2(mut,mut) [const mutable]\n"); // fallback to const/mutable
411
412        // if all const/nonconst combinations exist -> shall always pick exact match
413        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, con, con), "cwcb3(con,con) [const const]\n");     // exact match
414        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, mut, con), "cwcb3(mut,con) [mutable const]\n");   // exact match
415        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, con, mut), "cwcb3(con,mut) [const mutable]\n");   // exact match
416        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, mut, mut), "cwcb3(mut,mut) [mutable mutable]\n"); // exact match
417
418        // test reference arguments
419        int       imut = 17;
420        const int icon = 23;
421
422        const long lcon = 775L;
423
424        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, imut),  "cwcb1(17)\n");
425        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, icon),  "cwcb1(23)\n");
426        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &lcon), "cwcb1(775) [long ptr]\n");
427
428        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &icon), "cwcb1(23) [const ptr]\n");
429        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &icon), "cwcb1(23) [const ptr]\n");
430
431        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &imut), "cwcb1(17) [mutable ptr]\n"); // modifies 'imut'
432        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &imut), "cwcb1(34) [mutable ptr]\n"); // modifies 'imut'
433        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &imut), "cwcb1(68) [mutable ptr]\n"); // modifies 'imut'
434
435        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, mut),   "cwcb1(mut) [mutable]\n");
436        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, con),   "cwcb1(con) [const]\n");
437
438        free(mut);
439    }
440
441}
442
443#endif // UNIT_TESTS
444
445
Note: See TracBrowser for help on using the repository browser.