source: branches/lib/CORE/arb_string.cxx

Last change on this file was 19339, checked in by westram, 3 years ago
  • reintegrates 'refactor' into 'trunk'
    • eliminates old interface of GBS_strstruct
    • add a few new unittests (editor-config string + some PT-SERVER-functions)
  • adds: log:branches/refactor@19300:19338
File size: 17.5 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : arb_string.cxx                                     //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in November 2010   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#include "arb_string.h"
13
14#include <ctime>
15#include <sys/time.h>
16#include <Keeper.h>
17
18inline tm *get_current_time() {
19    timeval  date;
20    tm      *p;
21
22    gettimeofday(&date, NULp);
23
24#if defined(DARWIN)
25    struct timespec local;
26    TIMEVAL_TO_TIMESPEC(&date, &local); // not avail in time.h of Linux gcc 2.95.3
27    p = localtime(&local.tv_sec);
28#else
29    p = localtime(&date.tv_sec);
30#endif // DARWIN
31
32    return p;
33}
34
35const char *ARB_date_string() {
36    const char *date_string = NULp;
37#if defined(UNIT_TESTS)
38    if (RUNNING_TEST()) {
39        date_string = "Thu Nov 29 22:33:09 1973"; // timestamp used in unittests (=@123456789 CET)
40    }
41    else
42#endif
43    {
44        tm   *p        = get_current_time();
45        char *readable = asctime(p);          // points to a static buffer
46        char *cr       = strchr(readable, '\n');
47        arb_assert(cr);
48        cr[0]          = 0;                   // cut of \n
49        date_string    = readable;
50    }
51    return date_string;
52}
53
54const char *ARB_dateTime_suffix() {
55    /*! returns "YYYYMMDD_HHMMSS" */
56    const  unsigned  SUFFIXLEN = 8+1+6;
57    static char      buffer[SUFFIXLEN+1];
58    tm              *p         = get_current_time();
59
60#if defined(ASSERTION_USED)
61    size_t printed =
62#endif
63        strftime(buffer, SUFFIXLEN+1, "%Y%m%d_%H%M%S", p);
64    arb_assert(printed == SUFFIXLEN);
65    buffer[SUFFIXLEN] = 0;
66
67    return buffer;
68}
69
70// --------------------------------------------------------------------------------
71
72const char *ARB_keep_string(char *str) {
73    /*! keep an allocated string until program termination
74     * useful to avoid valgrind reporting leaks e.g for callback parameters
75     */
76    static Keeper<char*> stringKeeper;
77    stringKeeper.keep(str);
78    return str;
79}
80
81
82// --------------------------------------------------------------------------------
83
84
85#ifdef UNIT_TESTS
86
87#include <string>
88#include <climits>
89
90#ifndef TEST_UNIT_H
91#include <test_unit.h>
92#endif
93
94using namespace std;
95
96// ----------------------------------------------
97//      some tests for unit-test-code itself
98
99#define TEST_EXPECT_HEAPCOPY_EQUAL(copy,expected) do {  \
100        char *theCopy = (copy);                         \
101        TEST_EXPECT_EQUAL(theCopy, expected);           \
102        free(theCopy);                                  \
103    } while(0)
104
105void TEST_arbtest_strf() {
106    // tests string formatter from test_unit.h
107    using namespace arb_test;
108    TEST_EXPECT_HEAPCOPY_EQUAL(StaticCode::strf("<%i>", 7), "<7>");
109    TEST_EXPECT_HEAPCOPY_EQUAL(StaticCode::strf("<%0*i>", 3, 7), "<007>");
110}
111
112void TEST_arbtest_readable() {
113    using namespace arb_test;
114
115    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy('x')), "'x' (=0x78)");
116    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(static_cast<unsigned char>('x'))), "'x' (=0x78)");
117    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(static_cast<signed char>('x'))), "'x' (=0x78)");
118
119    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(true)), "true");
120    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(false)), "false");
121
122    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(1)), "1");
123    TEST_EXPECT_HEAPCOPY_EQUAL(val2hex(make_copy(2)), "0x2");
124
125    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(3L)), "3");
126    TEST_EXPECT_HEAPCOPY_EQUAL(val2hex(make_copy(4L)), "0x4");
127
128    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(5U)), "5");
129    TEST_EXPECT_HEAPCOPY_EQUAL(val2hex(make_copy(6U)), "0x6");
130
131    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy("some\ntext\twhich\"special\\chars")), "\"some\\ntext\\twhich\\\"special\\\\chars\"");
132    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy("a\x01\x02\x07\x08\x09\x0b\x0c\x0d\x1a\x22\x27\x5c\x7e\x7f\x80\xfe\xff")),
133                               /*                  */ "\"a\\1\\2\\a\\b\\t\\v\\f\\r\\x1a\\\"'\\\\~\\x7f\\x80\\xfe\\xff\"");
134    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy((const char *)NULp)), "(null)");
135    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy((const unsigned char *)NULp)), "(null)");
136    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy((const signed char *)NULp)), "(null)");
137
138    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(1.7)), "1.700000");
139    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(177.0e20)),  "17699999999999998951424.000000");
140    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(177.0e20F)), "17699999967695435988992.000000");
141}
142
143void TEST_arbtest_copyable() {
144    using namespace arb_test;
145
146    int         i = 7;
147    const char *s = "servas";
148
149    TEST_EXPECT(make_copy(i) == make_copy(7));
150    TEST_EXPECT_ZERO(strcmp(make_copy(s), make_copy("servas")));
151}
152
153#define TEST_DESCRIPTIONS(d, tt, tf, ft, ff) do {        \
154        TEST_EXPECT_EQUAL((d).make(true, true), (tt));   \
155        TEST_EXPECT_EQUAL((d).make(true, false), (tf));  \
156        TEST_EXPECT_EQUAL((d).make(false, true), (ft));  \
157        TEST_EXPECT_EQUAL((d).make(false, false), (ff)); \
158    } while(0)
159
160#define TEST_SIMPLE_DESCRIPTIONS(d, ae, nae) TEST_DESCRIPTIONS(d, ae, nae, ae, nae)
161
162void TEST_arbtest_predicate_description() {
163    TEST_SIMPLE_DESCRIPTIONS(predicate_description("similar"), "is similar", "isnt similar");
164    TEST_SIMPLE_DESCRIPTIONS(predicate_description("repairs"), "repairs", "doesnt repair");
165
166    TEST_DESCRIPTIONS(predicate_description("equals", "differs"),
167                      "equals", "doesnt equal",
168                      "doesnt differ", "differs");
169
170    TEST_DESCRIPTIONS(predicate_description("less_than", "more_than"),
171                      "is less_than", "isnt less_than",
172                      "isnt more_than", "is more_than");
173}
174
175void TEST_arbtest_expectations() {
176    // used to TDD expectations
177    using namespace arb_test;
178
179    string apple       = "Apfel";
180    string pear        = "Birne";
181    string boskop      = apple;
182    string pomegranate = "Granatapfel";
183
184    TEST_EXPECTATION(that(apple).is_equal_to("Apfel"));
185
186    TEST_EXPECTATION(that(apple).does_differ_from(pear));
187    TEST_EXPECTATION(that(apple).is_equal_to(boskop));
188    TEST_EXPECTATION(wrong(that(pomegranate).is_equal_to(apple)));
189
190    match_expectation ff1 = that(1.0).is_equal_to(2-1);
191    match_expectation ff2 = that(boskop).is_equal_to(apple);
192    match_expectation ff3 = that(apple).is_equal_to(apple);
193
194    match_expectation nf1 = that(apple).is_equal_to(pear);
195    match_expectation nf2 = that(pomegranate).is_equal_to(apple);
196    match_expectation nf3 = that(apple).does_differ_from(boskop);
197
198    match_expectation a1 = all().of(ff1);
199    match_expectation a2 = all().of(ff1, ff2);
200    match_expectation a3 = all().of(ff1, ff2, ff3);
201
202    TEST_EXPECTATION(a1);
203    TEST_EXPECTATION(a2);
204    TEST_EXPECTATION(a3);
205
206    match_expectation n1 = none().of(ff1);
207    match_expectation n2 = none().of(ff1, ff2);
208    match_expectation n3 = none().of(ff1, ff2, ff3);
209
210    TEST_EXPECTATION(wrong(none().of(that(boskop).is_equal_to(apple))));
211    TEST_EXPECTATION(wrong(n1));
212    TEST_EXPECTATION(wrong(n2));
213    TEST_EXPECTATION(wrong(n3));
214
215    TEST_EXPECTATION(atleast(1).of(a1));
216    TEST_EXPECTATION(atleast(1).of(a1, n1));
217    TEST_EXPECTATION(atleast(1).of(n2, a1, n1));
218
219    TEST_EXPECTATION(wrong(atleast(2).of(a1, n1, n2)));
220    TEST_EXPECTATION(wrong(atleast(2).of(a1, n1)));
221    TEST_EXPECTATION(wrong(atleast(2).of(a1))); // impossible
222
223    TEST_EXPECTATION(atmost(2).of(a1));
224    TEST_EXPECTATION(atmost(2).of(a1, a2));
225    TEST_EXPECTATION(atmost(2).of(a1, a2, n1));
226    TEST_EXPECTATION(atmost(2).of(a1, n1, n2));
227    TEST_EXPECTATION(atmost(2).of(n1, n2));
228    TEST_EXPECTATION(wrong(atmost(2).of(a1, a2, a3)));
229
230    TEST_EXPECTATION(exactly(1).of(ff1, nf1, nf2));
231    TEST_EXPECTATION(wrong(exactly(1).of(nf1, nf2)));
232    TEST_EXPECTATION(wrong(exactly(1).of(nf1, nf2, nf3)));
233    TEST_EXPECTATION(wrong(exactly(1).of(ff1, ff2, nf2)));
234    TEST_EXPECTATION(wrong(exactly(1).of(ff1, ff2, ff3)));
235
236}
237
238void TEST_expectation_groups() {
239    using namespace arb_test;
240
241    expectation_group no_expectations;
242    TEST_EXPECTATION(all().ofgroup(no_expectations));
243    TEST_EXPECTATION(none().ofgroup(no_expectations));
244
245    expectation_group fulfilled_expectation  (that(1).is_equal_to(1));
246    expectation_group unfulfilled_expectation(that(1).is_equal_to(0));
247    expectation_group some_fulfilled_expectations(that(1).is_equal_to(0), that(1).is_equal_to(1));
248
249    TEST_EXPECTATION(all().ofgroup(fulfilled_expectation));
250    TEST_EXPECTATION(none().ofgroup(unfulfilled_expectation));
251
252    TEST_EXPECT(none().ofgroup(fulfilled_expectation).unfulfilled());
253    TEST_EXPECT(all().ofgroup(unfulfilled_expectation).unfulfilled());
254
255    TEST_EXPECT(all().ofgroup(some_fulfilled_expectations).unfulfilled());
256    TEST_EXPECT(none().ofgroup(some_fulfilled_expectations).unfulfilled());
257}
258
259void TEST_replace_old_TEST_EXPECTS_by_expectations() {
260    // test various string-types are matchable (w/o casts)
261    {
262        const char *car_ccp = "Alfa";
263        char       *car_cp  = ARB_strdup("Alfa");
264        string      car_str("Alfa");
265
266        TEST_EXPECT_EQUAL(car_ccp, "Alfa");
267        TEST_EXPECT_EQUAL(car_cp, "Alfa");
268        TEST_EXPECT_EQUAL(car_str, "Alfa");
269
270        TEST_EXPECT_EQUAL("Alfa", car_ccp);
271        TEST_EXPECT_EQUAL("Alfa", car_cp);
272        TEST_EXPECT_EQUAL("Alfa", car_str);
273
274        TEST_EXPECT_EQUAL(car_cp, car_ccp);
275        TEST_EXPECT_EQUAL(car_cp, car_str);
276        TEST_EXPECT_EQUAL(car_ccp, car_cp);
277        TEST_EXPECT_EQUAL(car_ccp, car_str);
278        TEST_EXPECT_EQUAL(car_str, car_cp);
279        TEST_EXPECT_EQUAL(car_str, car_ccp);
280
281        char *null = NULp;
282        TEST_EXPECT_NULL((void*)NULp);
283        TEST_EXPECT_NULL(null);
284
285        TEST_EXPECT_CONTAINS(car_ccp, "lf");
286        TEST_EXPECT_CONTAINS(car_cp, "fa");
287        TEST_EXPECT_CONTAINS(car_str, "Al");
288
289        free(car_cp);
290    }
291
292    // test various numeric types are matchable
293
294    {
295        short unsigned su = 7;
296        short          s  = -su;
297
298        unsigned iu = su;
299        int      i  = -iu;
300
301        long unsigned lu = (long unsigned)INT_MAX+3;
302        long          l  = -lu;
303
304        float  f = s;
305        double d = i;
306
307        TEST_EXPECT_EQUAL(s, -7);
308        TEST_EXPECT_EQUAL(i, -7);
309
310        TEST_EXPECT_EQUAL(su, 7);  TEST_EXPECT_EQUAL(iu, 7);
311        TEST_EXPECT_EQUAL(su, 7U); TEST_EXPECT_EQUAL(iu, 7U);
312        TEST_EXPECT_EQUAL(su, 7L); TEST_EXPECT_EQUAL(iu, 7L);
313
314        TEST_EXPECT_EQUAL(s, -su); TEST_EXPECT_EQUAL(s, -iu);
315        TEST_EXPECT_EQUAL(i, -iu); TEST_EXPECT_EQUAL(i, -su);
316        TEST_EXPECT_EQUAL(l, -lu);
317
318        TEST_EXPECT_EQUAL(f, d);
319        TEST_EXPECT_EQUAL(d, f);
320    }
321
322    TEST_EXPECT_ZERO(7-7);
323}
324
325// --- simulate user_type (which may be defined anywhere) ---
326class user_type {
327    int x, y;
328public:
329    user_type(int X, int Y) : x(X), y(Y) {}
330
331    int get_x() const { return x; }
332    int get_y() const { return y; }
333
334    user_type flipped() const { return user_type(y,x); }
335
336    int quadrant() const {
337        if (x == 0 || y == 0) return 0; // on axis
338        if (y>0) return x<0 ? 2 : 1;
339        return x<0 ? 3 : 4;
340    }
341};
342// --- end of user_type ---
343
344// helpers needed for tests:
345inline bool operator == (const user_type& u1, const user_type& u2) { return u1.get_x() == u2.get_x() && u1.get_y() == u2.get_y(); }
346inline char *val2readable(const user_type& u) { return arb_test::StaticCode::strf("user_type(%i,%i)", u.get_x(), u.get_y()); }
347inline bool in_same_quadrant(const user_type& u1, const user_type& u2) { return u1.quadrant() == u2.quadrant(); }
348
349void TEST_user_type_with_expectations() {
350    user_type ut1(3, 4);
351    user_type ut12(4, 4);
352    user_type ut2(-4, 4);
353    user_type ut3(-4, -8);
354    user_type ut4(4, -8);
355
356    TEST_EXPECTATION(that(ut1).does_differ_from(ut12));
357    TEST_EXPECTATION(that(ut12).is_equal_to(ut12.flipped()));
358    TEST_EXPECTATION(that(ut1).does_differ_from(ut1.flipped()));
359
360    TEST_EXPECTATION(that(ut1).fulfills(in_same_quadrant, ut12));
361    TEST_EXPECTATION(none().of(that(ut1).fulfills(in_same_quadrant, ut2),
362                          that(ut2).fulfills(in_same_quadrant, ut3),
363                          that(ut3).fulfills(in_same_quadrant, ut4)));
364}
365TEST_PUBLISH(TEST_user_type_with_expectations);
366
367void TEST_similarity() {
368    double d1      = 0.7531;
369    double epsilon = 0.00001;
370    double d2      = d1-epsilon*0.6;
371    double d3      = d1+epsilon*0.6;
372
373    TEST_EXPECTATION(that(d1).fulfills(epsilon_similar(epsilon), d2));
374    TEST_EXPECTATION(that(d1).fulfills(epsilon_similar(epsilon), d3));
375    TEST_EXPECTATION(that(d2).contradicts(epsilon_similar(epsilon), d3));
376
377    TEST_EXPECT_SIMILAR(d1, d2, epsilon);
378    TEST_EXPECT_SIMILAR(d1, d3, epsilon);
379}
380
381void TEST_less_equal() {
382    int x = 7;
383    int y = 8;
384    int z = 9;
385
386    // less/more etc
387
388    TEST_EXPECTATION(that(x).is_less_than(y));
389    TEST_EXPECTATION(that(x).is_less_or_equal(y));
390    TEST_EXPECTATION(that(x).is_less_or_equal(x));
391
392    TEST_EXPECTATION(that(y).is_more_than(x));
393    TEST_EXPECTATION(that(y).is_more_or_equal(x));
394    TEST_EXPECTATION(that(y).is_more_or_equal(y));
395
396    TEST_EXPECT_LESS_EQUAL(x, y);
397    TEST_EXPECT_LESS_EQUAL(x, x);
398    TEST_EXPECT_LESS(x, y);
399    TEST_EXPECT_IN_RANGE(y, x, z);
400}
401TEST_PUBLISH(TEST_less_equal);
402
403class readModified { // modifies on "read" (used to test unwanted double-evaluation)
404    int val;
405public:
406    readModified(int v) : val(v) {}
407    void set(int n) { val = n; }
408    int getAndMod(int n) {
409        int v = val;
410        set(n);
411        return v;
412    }
413};
414
415#if !defined(__clang__)
416// TEST_DISABLED_CLANG: evaluation order differs under clang
417void TEST_single_eval() {
418    readModified mod(5);
419    TEST_EXPECT_EQUAL__BROKEN(mod.getAndMod(2), 2, 5); // now succeeds (this is no broken test; it tests behavior of TEST_EXPECT_EQUAL__BROKEN!)
420
421    mod.set(5);
422    TEST_EXPECT_IN_RANGE(mod.getAndMod(10), 4, 6);
423    TEST_EXPECT_EQUAL(mod.getAndMod(10), 10);
424    TEST_EXPECT_IN_RANGE__BROKEN(mod.getAndMod(2), 8, 12); // @@@ tested expression is evaluated twice
425    TEST_EXPECT_EQUAL(mod.getAndMod(2), 2);
426    TEST_EXPECT_IN_RANGE(mod.getAndMod(33), 1, 3);
427    TEST_EXPECT_EQUAL(mod.getAndMod(33), 33);
428    TEST_EXPECT_IN_RANGE__BROKEN(mod.getAndMod(20), 32, 34); // @@@ tested expression is evaluated twice
429    TEST_EXPECT_EQUAL(mod.getAndMod(20), 20);
430}
431#endif
432
433enum MyEnum {
434    MY_UNKNOWN,
435    MY_RNA,
436    MY_DNA,
437    MY_AA,
438};
439
440void TEST_MyEnum_loop() {
441    int loops_performed = 0;
442    const char *db_name[]=  { NULp, "TEST_trees.arb", "TEST_realign.arb", "TEST_realign.arb", NULp };
443    for (int iat = MY_RNA; iat<=MY_AA; ++iat) {
444        MyEnum at = MyEnum(iat);
445        TEST_EXPECT(at>=1 && at<=3);
446        fprintf(stderr, "at=%i db_name[%i]='%s'\n", at, at, db_name[at]);
447        TEST_REJECT_NULL(db_name[at]);
448        loops_performed++;
449    }
450    TEST_EXPECT_EQUAL(loops_performed, 3);
451}
452
453
454void TEST_ARB_strchrnul() {
455    const char *check = "check";
456
457    TEST_EXPECT_EQUAL(ARB_strchrnul("check", 'c'),  "check");
458    TEST_EXPECT_EQUAL(ARB_strchrnul("check", 'e'),  "eck");
459    TEST_EXPECT_EQUAL(ARB_strchrnul("check", 'i'),  "");
460    TEST_EXPECT_EQUAL(ARB_strchrnul("check", '\0'), "");
461
462    TEST_EXPECT_EQUAL(ARB_strchrnul(check, 'c'),  "check");
463    TEST_EXPECT_EQUAL(ARB_strchrnul(check, 'e'),  "eck");
464    TEST_EXPECT_EQUAL(ARB_strchrnul(check, 'i'),  "");
465    TEST_EXPECT_EQUAL(ARB_strchrnul(check, '\0'), "");
466
467    TEST_EXPECT(ARB_strchrnul(check, 'c')  == check);
468    TEST_EXPECT(ARB_strchrnul(check, 'e')  == (check+2));
469    TEST_EXPECT(ARB_strchrnul(check, 'i')  == (check+5));
470    TEST_EXPECT(ARB_strchrnul(check, '\0') == (check+5));
471}
472
473static const char *keepOne(char *s) {
474    static char *s2 = NULp;
475    reassign(s2, s);
476    return s2;
477}
478
479#define TEST_EXPECT_STRPARTDUP_TO(start,end,expected) TEST_EXPECT_EQUAL(keepOne(ARB_strpartdup(start,end)),expected)
480#define TEST_EXPECT_STRNDUP_TO(start,len,expected)    TEST_EXPECT_EQUAL(keepOne(ARB_strndup(start,len)),expected)
481
482void TEST_string_duppers() {
483    const char *text  = "text";
484    const char *empty = "";
485
486    TEST_EXPECT_STRPARTDUP_TO(text, text+4, text); // dup with 0-byte
487    TEST_EXPECT_STRPARTDUP_TO(text, text+3, text); // dup w/o 0-byte (afterwards append 0-byte)
488    TEST_EXPECT_STRPARTDUP_TO(text, text,   "t");
489    TEST_EXPECT_STRPARTDUP_TO(text, text-1, empty);
490
491    // copy whole string
492    TEST_EXPECT_STRPARTDUP_TO(text,  NULp, text);
493    TEST_EXPECT_STRPARTDUP_TO(empty, NULp, empty);
494
495    TEST_EXPECT_STRNDUP_TO(text, 5, text); // dup with 0-byte
496    TEST_EXPECT_STRNDUP_TO(text, 4, text); // dup w/o 0-byte (afterwards append 0-byte)
497    TEST_EXPECT_STRNDUP_TO(text, 1, "t");
498    TEST_EXPECT_STRNDUP_TO(text, 0, empty);
499
500    // error cases:
501    // a. "less" than empty string
502    TEST_EXPECT_NULL(ARB_strpartdup(text, text-2));
503    TEST_EXPECT_NULL(ARB_strpartdup(text, text-200));
504
505    TEST_EXPECT_NULL(ARB_strndup(text, -1));
506    TEST_EXPECT_NULL(ARB_strndup(text, -1000));
507
508    // b. no source -> no result
509    TEST_EXPECT_STRPARTDUP_TO(NULp, empty, NULp);
510    TEST_EXPECT_STRPARTDUP_TO(NULp, text,  NULp);
511    TEST_EXPECT_STRPARTDUP_TO(NULp, NULp,  NULp);
512
513    keepOne(NULp); // =free
514}
515TEST_PUBLISH(TEST_string_duppers);
516
517#endif // UNIT_TESTS
518
519// --------------------------------------------------------------------------------
520
521
Note: See TracBrowser for help on using the repository browser.