source: tags/ms_r16q3/SL/CB/cb.cxx

Last change on this file was 14479, checked in by westram, 8 years ago
  • add new typed callback style w/o fixed argument
    • add unit tests for callback style
File size: 17.9 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
103DECLARE_CBTYPE_VV_AND_BUILDERS(CustomCallback, void); // defines makeCustomCallback
104
105static uint32_t traceChecksum;
106const int       BUFFERSIZE = 100;
107char            traceBuffer[BUFFERSIZE];
108
109__ATTR__FORMAT(1) static void tracef(const char *format, ...) {
110    va_list parg;
111    va_start(parg, format);
112    int printed = vsnprintf(traceBuffer, BUFFERSIZE, format, parg);
113    va_end(parg);
114
115#if defined(TRACE)
116    fputs(traceBuffer, stdout);
117#endif
118    if (printed >= BUFFERSIZE) {
119        printf("\nprinted=%i\n", printed);
120    }
121    TEST_EXPECT(printed<BUFFERSIZE);
122
123    traceChecksum = 0;
124    for (int p = 0; p<printed; ++p) {
125        traceChecksum = (traceChecksum<<1)^(traceChecksum>>31)^traceBuffer[p];
126    }
127}
128
129static AW_root    *fake_root   = (AW_root*)1;
130static AW_window  *fake_win    = (AW_window*)2;
131static GBDATA     *fake_gbd    = (GBDATA*)3;
132static AW_awar    *fake_awar   = (AW_awar*)4;
133static bool        fake_bool   = false;
134static GB_CB_TYPE  fake_gbtype = GB_CB_CHANGED;
135
136static void rcb0(AW_root *r) {
137    TEST_EXPECT(r == fake_root);
138    tracef("rcb0()\n");
139}
140static void rcb1(AW_root *r, const char *name) {
141    TEST_EXPECT(r == fake_root);
142    tracef("rcb1(%s)\n", name);
143}
144static void rcb2(AW_root *r, const char *name, int val) {
145    TEST_EXPECT(r == fake_root);
146    tracef("rcb2(%s=%i) [int]\n", name, val);
147}
148static void rcb2(AW_root *r, const char *name, long val) {
149    TEST_EXPECT(r == fake_root);
150    tracef("rcb2(%s=%li) [long]\n", name, val);
151}
152
153static void wcb0(AW_window *w) {
154    TEST_EXPECT(w == fake_win);
155    tracef("wcb0()\n");
156}
157static void wcb1(AW_window *w, const char *name) {
158    TEST_EXPECT(w == fake_win);
159    tracef("wcb1(%s)\n", name);
160}
161static void wcb1(AW_window *w, string *name) {
162    TEST_EXPECT(w == fake_win);
163    tracef("wcb1(%s) [string]\n", name->c_str());
164}
165static void wcb2(AW_window *w, const char *name, const char *val) {
166    TEST_EXPECT(w == fake_win);
167    tracef("wcb2(%s=%s) [const char/const char]\n", name, val);
168}
169static void wcb2(AW_window *w, const string *name, const string *val) {
170    TEST_EXPECT(w == fake_win);
171    tracef("wcb2(%s=%s) [string/string]\n", name->c_str(), val->c_str());
172}
173static void wcb2(AW_window *w, const char *name, int val) {
174    TEST_EXPECT(w == fake_win);
175    tracef("wcb2(%s=%i) [int]\n", name, val);
176}
177static void wcb2(AW_window *w, const char *name, long val) {
178    TEST_EXPECT(w == fake_win);
179    tracef("wcb2(%s=%li) [long]\n", name, val);
180}
181static void wcb2(AW_window *w, char c, long long val) {
182    TEST_EXPECT(w == fake_win);
183    tracef("wcb2(%c=%lli) [long long]\n", c, val);
184}
185
186static void tacb0(AW_awar *a) {
187    TEST_EXPECT(a == fake_awar);
188    tracef("tacb0()\n");
189}
190static void tacb1(AW_awar *a, bool b) {
191    TEST_EXPECT(a == fake_awar);
192    TEST_EXPECT(b == fake_bool);
193    tracef("tacb1()\n");
194}
195static void tacb2(AW_awar *a, bool b, const char *name) {
196    TEST_EXPECT(a == fake_awar);
197    TEST_EXPECT(b == fake_bool);
198    tracef("tacb2(%s)\n", name);
199}
200static void tacb2(AW_awar *a, bool b, int val) {
201    TEST_EXPECT(a == fake_awar);
202    TEST_EXPECT(b == fake_bool);
203    tracef("tacb2(%i)\n", val);
204}
205
206static void ucb0(UNFIXED) {
207    tracef("ucb0()\n");
208}
209static void ucb1(UNFIXED, const char *name) {
210    tracef("ucb1(%s)\n", name);
211}
212static void ucb2(UNFIXED, const char *name, int val) {
213    tracef("ucb2(%s=%i) [int]\n", name, val);
214}
215static void ucb2(UNFIXED, const char *name, long val) {
216    tracef("ucb2(%s=%li) [long]\n", name, val);
217}
218
219static AW_window *cwcb0(AW_root *r) {
220    TEST_EXPECT(r == fake_root);
221    tracef("cwcb0()\n");
222    return fake_win;
223}
224static AW_window *cwcb1(AW_root *r, int x) {
225    TEST_EXPECT(r == fake_root);
226    tracef("cwcb1(%i)\n", x);
227    return fake_win;
228}
229static AW_window *cwcb1(AW_root *r, const long *lp) {
230    TEST_EXPECT(r == fake_root);
231    tracef("cwcb1(%li) [long ptr]\n", *lp);
232    return fake_win;
233}
234static AW_window *cwcb1(AW_root *r, const int *x) {
235    TEST_EXPECT(r == fake_root);
236    tracef("cwcb1(%i) [const ptr]\n", *x);
237    return fake_win;
238}
239static AW_window *cwcb1(AW_root *r, int *x) {
240    TEST_EXPECT(r == fake_root);
241    tracef("cwcb1(%i) [mutable ptr]\n", *x);
242    *x *= 2; // modify callback argument!
243    return fake_win;
244}
245static AW_window *cwcb1(AW_root *r, char* s) {
246    TEST_EXPECT(r == fake_root);
247    tracef("cwcb1(%s) [mutable]\n", s);
248    return fake_win;
249}
250static AW_window *cwcb1(AW_root *r, const char* s) {
251    TEST_EXPECT(r == fake_root);
252    tracef("cwcb1(%s) [const]\n", s);
253    return fake_win;
254}
255static AW_window *cwcb2(AW_root *r, const char *s1, const char *s2) {
256    TEST_EXPECT(r == fake_root);
257    tracef("cwcb2(%s,%s) [const const]\n", s1, s2);
258    return fake_win;
259}
260static AW_window *cwcb2(AW_root *r, const char *s1, char *s2) {
261    TEST_EXPECT(r == fake_root);
262    tracef("cwcb2(%s,%s) [const mutable]\n", s1, s2);
263    return fake_win;
264}
265
266static AW_window *cwcb3(AW_root *r, const char *s1, const char *s2) {
267    TEST_EXPECT(r == fake_root);
268    tracef("cwcb3(%s,%s) [const const]\n", s1, s2);
269    return fake_win;
270}
271static AW_window *cwcb3(AW_root *r, const char *s1, char *s2) {
272    TEST_EXPECT(r == fake_root);
273    tracef("cwcb3(%s,%s) [const mutable]\n", s1, s2);
274    return fake_win;
275}
276static AW_window *cwcb3(AW_root *r, char *s1, const char *s2) {
277    TEST_EXPECT(r == fake_root);
278    tracef("cwcb3(%s,%s) [mutable const]\n", s1, s2);
279    return fake_win;
280}
281static AW_window *cwcb3(AW_root *r, char *s1, char *s2) {
282    TEST_EXPECT(r == fake_root);
283    tracef("cwcb3(%s,%s) [mutable mutable]\n", s1, s2);
284    return fake_win;
285}
286
287static void dbcb01(GBDATA *gbd) {
288    TEST_EXPECT(gbd == fake_gbd);
289    tracef("dbcb01()\n");
290}
291static void dbcb012(GBDATA *gbd, GB_CB_TYPE t) {
292    TEST_EXPECT(gbd == fake_gbd && t == fake_gbtype);
293    tracef("dbcb012()\n");
294}
295static void dbcb02(GB_CB_TYPE t) {
296    tracef("dbcb02(%i)\n", int(t));
297}
298static void dbcb1(GBDATA *gbd, int x, GB_CB_TYPE t) {
299    TEST_EXPECT(gbd == fake_gbd && t == fake_gbtype);
300    tracef("dbcb1(%i) [int]\n", x);
301}
302static void dbcb1(GBDATA *gbd, const char *n, GB_CB_TYPE t) {
303    TEST_EXPECT(gbd == fake_gbd && t == fake_gbtype);
304    tracef("dbcb1(%s) [const char]\n", n);
305}
306
307static void ccb11(const char *str) {
308    tracef("ccb11(%s)\n", str);
309}
310static void ccb12(int i) {
311    tracef("ccb12(%i)\n", i);
312}
313static void ccb2(int i, const char *str) {
314    tracef("ccb2(%i,%s)\n", i, str);
315}
316
317static void plaincb() {
318    tracef("plaincb()\n");
319}
320static AW_window *cwcb_plain() {
321    tracef("cwcb_plain()\n");
322    return fake_win;
323}
324
325inline void call(const RootCallback& rcb) { rcb(fake_root); }
326inline void call(const WindowCallback& wcb) { wcb(fake_win); }
327inline void call(const CreateWindowCallback& cwcb) { TEST_EXPECT(cwcb(fake_root) == fake_win); }
328inline void call(const DatabaseCallback& dbcb) { dbcb(fake_gbd, fake_gbtype); }
329inline void call(const TreeAwarCallback& tacb) { tacb(fake_awar, fake_bool); }
330inline void call(const CustomCallback& ccb) { ccb(); }
331
332#define TEST_CB(cb,expectedChecksum) do {                               \
333        traceChecksum = -666;                                           \
334        call(cb);                                                       \
335        TEST_EXPECT_EQUAL(traceChecksum, (uint32_t)expectedChecksum);   \
336    } while(0)
337
338#define TEST_CB_TRACE(cb,expectedOutput) do {           \
339        call(cb);                                       \
340        TEST_EXPECT_EQUAL(traceBuffer, expectedOutput); \
341    } while(0)
342
343#define TEST_CB_TRACE__BROKEN(cb,expectedOutput) do {           \
344        call(cb);                                               \
345        TEST_EXPECT_EQUAL__BROKEN(traceBuffer, expectedOutput); \
346    } while(0)
347
348
349static void freeCharp(char *str) { free(str); }
350static void freeCharp(char *str1, char *str2) { free(str1); free(str2); }
351static void deleteString(string *str) { delete str; }
352static void deleteString(string *str1, string *str2) { delete str1; delete str2; }
353
354void TEST_cbs() {
355    // MISSING_TEST("please log");
356    // for (int i = 0; i<100000; ++i)
357    {
358        TEST_CB_TRACE(makeRootCallback(plaincb),             "plaincb()\n");
359        TEST_CB_TRACE(makeRootCallback(rcb0),                "rcb0()\n");
360        TEST_CB_TRACE(makeRootCallback(rcb1,  "dispatched"), "rcb1(dispatched)\n");
361        TEST_CB_TRACE(makeRootCallback(rcb2, "age",  46),    "rcb2(age=46) [int]\n");
362        TEST_CB_TRACE(makeRootCallback(rcb2, "size", 178L),  "rcb2(size=178) [long]\n");
363
364        TEST_CB_TRACE(makeWindowCallback(plaincb),            "plaincb()\n");
365        TEST_CB_TRACE(makeWindowCallback(wcb0),               "wcb0()\n");
366        TEST_CB_TRACE(makeWindowCallback(wcb1, "dispatched"), "wcb1(dispatched)\n");
367        TEST_CB_TRACE(makeWindowCallback(wcb2, "age",  46),   "wcb2(age=46) [int]\n");
368        TEST_CB_TRACE(makeWindowCallback(wcb2, "size", 178L), "wcb2(size=178) [long]\n");
369
370        TEST_CB_TRACE(makeTreeAwarCallback(plaincb),             "plaincb()\n");
371        TEST_CB_TRACE(makeTreeAwarCallback(tacb0),               "tacb0()\n");
372        TEST_CB_TRACE(makeTreeAwarCallback(tacb1),               "tacb1()\n");
373        TEST_CB_TRACE(makeTreeAwarCallback(tacb2, "dispatched"), "tacb2(dispatched)\n");
374        TEST_CB_TRACE(makeTreeAwarCallback(tacb2, 46),           "tacb2(46)\n");
375
376        // declaring a cb with UNFIXED as fixed-argument allows to use callbacks as RootCallback AND as WindowCallback
377        // (when we use sigc++ in the future this should be changed to allowing functions w/o the UNFIXED-parameter)
378
379        TEST_CB_TRACE(makeRootCallback(ucb0),                "ucb0()\n");
380        TEST_CB_TRACE(makeRootCallback(ucb1,  "dispatched"), "ucb1(dispatched)\n");
381        TEST_CB_TRACE(makeRootCallback(ucb2, "age",  46),    "ucb2(age=46) [int]\n");
382        TEST_CB_TRACE(makeRootCallback(ucb2, "size", 178L),  "ucb2(size=178) [long]\n");
383
384        TEST_CB_TRACE(makeWindowCallback(ucb0),                "ucb0()\n");
385        TEST_CB_TRACE(makeWindowCallback(ucb1,  "dispatched"), "ucb1(dispatched)\n");
386        TEST_CB_TRACE(makeWindowCallback(ucb2, "age",  46),    "ucb2(age=46) [int]\n");
387        TEST_CB_TRACE(makeWindowCallback(ucb2, "size", 178L),  "ucb2(size=178) [long]\n");
388
389#if defined(ARB_64)
390        TEST_CB_TRACE(makeWindowCallback(wcb2, 'l', 49710827735915452LL),  "wcb2(l=49710827735915452) [long long]\n");
391#endif
392
393        TEST_CB_TRACE(makeCreateWindowCallback(cwcb_plain), "cwcb_plain()\n");
394        TEST_CB_TRACE(makeCreateWindowCallback(cwcb0),      "cwcb0()\n");
395        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, 77),  "cwcb1(77)\n");
396
397        // TEST_CB(makeDatabaseCallback(plaincb), 44760); // does not work (ambiguous due to 2 fixed arguments of DatabaseCallback)
398        TEST_CB_TRACE(makeDatabaseCallback(dbcb01),    "dbcb01()\n");
399        TEST_CB_TRACE(makeDatabaseCallback(dbcb012),   "dbcb012()\n");
400        TEST_CB_TRACE(makeDatabaseCallback(dbcb02),    "dbcb02(2)\n"); // call dbcb02 with fixed argument (i.e. with argument normally passed by ARBDB)
401        TEST_CB_TRACE(makeDatabaseCallback(dbcb1, 77), "dbcb1(77) [int]\n");
402
403        TEST_CB_TRACE(makeDatabaseCallback(dbcb1, freeCharp, strdup("test")), "dbcb1(test) [const char]\n");
404
405        // callbacks with deallocator
406
407        // TEST_CB(makeWindowCallback(wcb1, strdup("leak")), 0x163ac); // leaks
408        TEST_CB_TRACE(makeWindowCallback(wcb1, freeCharp, strdup("leak")), "wcb1(leak)\n");
409        // TEST_CB(makeWindowCallback(wcb1, freeCharp, "leak"), 0x163ac); // does not compile (can't call freeCharp with const char *)
410        TEST_CB_TRACE(makeWindowCallback(wcb1, deleteString, new string("leak")), "wcb1(leak) [string]\n");
411        // TEST_CB(makeWindowCallback(wcb2, strdup("hue"), strdup("hott")), 0xe09d7b1); // leaks
412        TEST_CB_TRACE(makeWindowCallback(wcb2, freeCharp, strdup("hue"), strdup("hott")), "wcb2(hue=hott) [const char/const char]\n");
413        TEST_CB_TRACE(makeWindowCallback(wcb2, deleteString, new string("hue"), new string("hott")), "wcb2(hue=hott) [string/string]\n");
414
415        // test const vs non-const pointers:
416        char       *mut = strdup("mut");
417        const char *con = "con";
418
419        // if only const/const and const/mutable exists -> shall always select as much mutable as possible
420        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, con, con), "cwcb2(con,con) [const const]\n");   // exact match
421        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, mut, con), "cwcb2(mut,con) [const const]\n");   // fallback to const/const
422        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, con, mut), "cwcb2(con,mut) [const mutable]\n"); // exact match
423        TEST_CB_TRACE(makeCreateWindowCallback(cwcb2, mut, mut), "cwcb2(mut,mut) [const mutable]\n"); // fallback to const/mutable
424
425        // if all const/nonconst combinations exist -> shall always pick exact match
426        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, con, con), "cwcb3(con,con) [const const]\n");     // exact match
427        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, mut, con), "cwcb3(mut,con) [mutable const]\n");   // exact match
428        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, con, mut), "cwcb3(con,mut) [const mutable]\n");   // exact match
429        TEST_CB_TRACE(makeCreateWindowCallback(cwcb3, mut, mut), "cwcb3(mut,mut) [mutable mutable]\n"); // exact match
430
431        // test reference arguments
432        int       imut = 17;
433        const int icon = 23;
434
435        const long lcon = 775L;
436
437        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, imut),  "cwcb1(17)\n");
438        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, icon),  "cwcb1(23)\n");
439        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &lcon), "cwcb1(775) [long ptr]\n");
440
441        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &icon), "cwcb1(23) [const ptr]\n");
442        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &icon), "cwcb1(23) [const ptr]\n");
443
444        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &imut), "cwcb1(17) [mutable ptr]\n"); // modifies 'imut'
445        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &imut), "cwcb1(34) [mutable ptr]\n"); // modifies 'imut'
446        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, &imut), "cwcb1(68) [mutable ptr]\n"); // modifies 'imut'
447
448        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, mut),   "cwcb1(mut) [mutable]\n");
449        TEST_CB_TRACE(makeCreateWindowCallback(cwcb1, con),   "cwcb1(con) [const]\n");
450
451        free(mut);
452
453        // test callbacks w/o fixed argument
454        TEST_CB_TRACE(makeCustomCallback(plaincb),             "plaincb()\n");
455        TEST_CB_TRACE(makeCustomCallback(ccb11, "helo"),       "ccb11(helo)\n");
456        TEST_CB_TRACE(makeCustomCallback(ccb12, 4711),         "ccb12(4711)\n");
457        TEST_CB_TRACE(makeCustomCallback(ccb2,  4711, "helo"), "ccb2(4711,helo)\n");
458
459        TEST_CB_TRACE(makeCustomCallback(ccb11, freeCharp, strdup("dup")), "ccb11(dup)\n");
460    }
461
462}
463TEST_PUBLISH(TEST_cbs);
464
465#endif // UNIT_TESTS
466
467
Note: See TracBrowser for help on using the repository browser.