source: tags/ms_r16q2/CORE/arb_string.cxx

Last change on this file was 14256, checked in by westram, 9 years ago
File size: 15.2 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 <arb_assert.h>
15
16#include <cstring>
17#include <cstdlib>
18
19#include <ctime>
20#include <sys/time.h>
21#include <Keeper.h>
22
23char *GB_strduplen(const char *p, unsigned len) {
24    // fast replacement for strdup, if len is known
25    if (p) {
26        char *neu;
27
28        arb_assert(strlen(p) == len);
29        // Note: Common reason for failure: a zero-char was manually printed by a GBS_global_string...-function
30
31        neu = (char*)malloc(len+1);
32        memcpy(neu, p, len+1);
33        return neu;
34    }
35    return 0;
36}
37
38char *GB_strpartdup(const char *start, const char *end) {
39    /* strdup of a part of a string (including 'start' and 'end')
40     * 'end' may point behind end of string -> copy only till zero byte
41     * if 'end'=('start'-1) -> return ""
42     * if 'end'<('start'-1) -> return 0
43     * if 'end' == NULL -> copy whole string
44     */
45
46    char *result;
47    if (end) {
48        int len = end-start+1;
49
50        if (len >= 0) {
51            const char *eos = (const char *)memchr(start, 0, len);
52
53            if (eos) len = eos-start;
54            result = (char*)malloc(len+1);
55            memcpy(result, start, len);
56            result[len] = 0;
57        }
58        else {
59            result = 0;
60        }
61    }
62    else { // end = 0 -> return copy of complete string
63        result = nulldup(start);
64    }
65
66    return result;
67}
68
69char *GB_strndup(const char *start, int len) {
70    return GB_strpartdup(start, start+len-1);
71}
72
73inline tm *get_current_time() {
74    timeval  date;
75    tm      *p;
76
77    gettimeofday(&date, 0);
78
79#if defined(DARWIN)
80    struct timespec local;
81    TIMEVAL_TO_TIMESPEC(&date, &local); // not avail in time.h of Linux gcc 2.95.3
82    p = localtime(&local.tv_sec);
83#else
84    p = localtime(&date.tv_sec);
85#endif // DARWIN
86
87    return p;
88}
89
90const char *GB_date_string() {
91    tm   *p        = get_current_time();
92    char *readable = asctime(p); // points to a static buffer
93    char *cr       = strchr(readable, '\n');
94    arb_assert(cr);
95    cr[0]          = 0;          // cut of \n
96
97    return readable;
98}
99
100const char *GB_dateTime_suffix() {
101    /*! returns "YYYYMMDD_HHMMSS" */
102    const  unsigned  SUFFIXLEN = 8+1+6;
103    static char      buffer[SUFFIXLEN+1];
104    tm              *p         = get_current_time();
105
106#if defined(ASSERTION_USED)
107    size_t printed =
108#endif
109        strftime(buffer, SUFFIXLEN+1, "%Y%m%d_%H%M%S", p);
110    arb_assert(printed == SUFFIXLEN);
111    buffer[SUFFIXLEN] = 0;
112
113    return buffer;
114}
115
116// --------------------------------------------------------------------------------
117
118const char *GB_keep_string(char *str) {
119    /*! keep an allocated string until program termination
120     * useful to avoid valgrind reporting leaks e.g for callback parameters
121     */
122    static Keeper<char*> stringKeeper;
123    stringKeeper.keep(str);
124    return str;
125}
126
127
128// --------------------------------------------------------------------------------
129
130
131#ifdef UNIT_TESTS
132
133#include <string>
134#include <climits>
135
136#ifndef TEST_UNIT_H
137#include <test_unit.h>
138#endif
139
140using namespace std;
141
142// ----------------------------------------------
143//      some tests for unit-test-code itself
144
145#define TEST_EXPECT_HEAPCOPY_EQUAL(copy,expected) do {  \
146        char *theCopy = (copy);                         \
147        TEST_EXPECT_EQUAL(theCopy, expected);           \
148        free(theCopy);                                  \
149    } while(0)
150
151void TEST_arbtest_strf() {
152    // tests string formatter from test_unit.h
153    using namespace arb_test;
154    TEST_EXPECT_HEAPCOPY_EQUAL(StaticCode::strf("<%i>", 7), "<7>");
155    TEST_EXPECT_HEAPCOPY_EQUAL(StaticCode::strf("<%0*i>", 3, 7), "<007>");
156}
157
158void TEST_arbtest_readable() {
159    using namespace arb_test;
160
161    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy('x')), "'x' (=0x78)");
162    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(static_cast<unsigned char>('x'))), "'x' (=0x78)");
163    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(static_cast<signed char>('x'))), "'x' (=0x78)");
164
165    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(true)), "true");
166    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(false)), "false");
167   
168    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(1)), "1");
169    TEST_EXPECT_HEAPCOPY_EQUAL(val2hex(make_copy(2)), "0x2");
170
171    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(3L)), "3");
172    TEST_EXPECT_HEAPCOPY_EQUAL(val2hex(make_copy(4L)), "0x4");
173
174    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(5U)), "5");
175    TEST_EXPECT_HEAPCOPY_EQUAL(val2hex(make_copy(6U)), "0x6");
176   
177    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy("some\ntext\twhich\"special\\chars")), "\"some\\ntext\\twhich\\\"special\\\\chars\"");
178    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy("a\1\2\x1a\x7e\x7f\x80\xfe\xff")), "\"a\\1\\2\\x1a~\\x7f\\x80\\xfe\\xff\"");
179    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy((const char *)NULL)), "(null)");
180    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy((const unsigned char *)NULL)), "(null)");
181    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy((const signed char *)NULL)), "(null)");
182
183    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(1.7)), "1.700000");
184    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(177.0e20)),  "17699999999999998951424.000000");
185    TEST_EXPECT_HEAPCOPY_EQUAL(val2readable(make_copy(177.0e20F)), "17699999967695435988992.000000");
186}
187
188void TEST_arbtest_copyable() {
189    using namespace arb_test;
190
191    int         i = 7;
192    const char *s = "servas";
193
194    TEST_EXPECT(make_copy(i) == make_copy(7));
195    TEST_EXPECT_ZERO(strcmp(make_copy(s), make_copy("servas")));
196}
197
198#define TEST_DESCRIPTIONS(d, tt, tf, ft, ff) do {        \
199        TEST_EXPECT_EQUAL((d).make(true, true), (tt));   \
200        TEST_EXPECT_EQUAL((d).make(true, false), (tf));  \
201        TEST_EXPECT_EQUAL((d).make(false, true), (ft));  \
202        TEST_EXPECT_EQUAL((d).make(false, false), (ff)); \
203    } while(0)
204
205#define TEST_SIMPLE_DESCRIPTIONS(d, ae, nae) TEST_DESCRIPTIONS(d, ae, nae, ae, nae)
206
207void TEST_arbtest_predicate_description() {
208    TEST_SIMPLE_DESCRIPTIONS(predicate_description("similar"), "is similar", "isnt similar");
209    TEST_SIMPLE_DESCRIPTIONS(predicate_description("repairs"), "repairs", "doesnt repair");
210
211    TEST_DESCRIPTIONS(predicate_description("equals", "differs"),
212                      "equals", "doesnt equal",
213                      "doesnt differ", "differs");
214
215    TEST_DESCRIPTIONS(predicate_description("less_than", "more_than"),
216                      "is less_than", "isnt less_than",
217                      "isnt more_than", "is more_than");
218}
219
220void TEST_arbtest_expectations() {
221    // used to TDD expectations
222    using namespace arb_test;
223
224    string apple       = "Apfel";
225    string pear        = "Birne";
226    string boskop      = apple;
227    string pomegranate = "Granatapfel";
228
229    TEST_EXPECTATION(that(apple).is_equal_to("Apfel"));
230   
231    TEST_EXPECTATION(that(apple).does_differ_from(pear));
232    TEST_EXPECTATION(that(apple).is_equal_to(boskop));
233    TEST_EXPECTATION(wrong(that(pomegranate).is_equal_to(apple)));
234
235    match_expectation ff1 = that(1.0).is_equal_to(2-1);
236    match_expectation ff2 = that(boskop).is_equal_to(apple);
237    match_expectation ff3 = that(apple).is_equal_to(apple);
238
239    match_expectation nf1 = that(apple).is_equal_to(pear);
240    match_expectation nf2 = that(pomegranate).is_equal_to(apple);
241    match_expectation nf3 = that(apple).does_differ_from(boskop);
242
243    match_expectation a1 = all().of(ff1);
244    match_expectation a2 = all().of(ff1, ff2);
245    match_expectation a3 = all().of(ff1, ff2, ff3);
246
247    TEST_EXPECTATION(a1);
248    TEST_EXPECTATION(a2);
249    TEST_EXPECTATION(a3);
250
251    match_expectation n1 = none().of(ff1);
252    match_expectation n2 = none().of(ff1, ff2);
253    match_expectation n3 = none().of(ff1, ff2, ff3);
254
255    TEST_EXPECTATION(wrong(none().of(that(boskop).is_equal_to(apple))));
256    TEST_EXPECTATION(wrong(n1));
257    TEST_EXPECTATION(wrong(n2));
258    TEST_EXPECTATION(wrong(n3));
259
260    TEST_EXPECTATION(atleast(1).of(a1));
261    TEST_EXPECTATION(atleast(1).of(a1, n1));
262    TEST_EXPECTATION(atleast(1).of(n2, a1, n1));
263
264    TEST_EXPECTATION(wrong(atleast(2).of(a1, n1, n2)));
265    TEST_EXPECTATION(wrong(atleast(2).of(a1, n1)));
266    TEST_EXPECTATION(wrong(atleast(2).of(a1))); // impossible
267
268    TEST_EXPECTATION(atmost(2).of(a1));
269    TEST_EXPECTATION(atmost(2).of(a1, a2));
270    TEST_EXPECTATION(atmost(2).of(a1, a2, n1));
271    TEST_EXPECTATION(atmost(2).of(a1, n1, n2));
272    TEST_EXPECTATION(atmost(2).of(n1, n2));
273    TEST_EXPECTATION(wrong(atmost(2).of(a1, a2, a3)));
274
275    TEST_EXPECTATION(exactly(1).of(ff1, nf1, nf2));
276    TEST_EXPECTATION(wrong(exactly(1).of(nf1, nf2)));
277    TEST_EXPECTATION(wrong(exactly(1).of(nf1, nf2, nf3)));
278    TEST_EXPECTATION(wrong(exactly(1).of(ff1, ff2, nf2)));
279    TEST_EXPECTATION(wrong(exactly(1).of(ff1, ff2, ff3)));
280
281}
282
283void TEST_expectation_groups() {
284    using namespace arb_test;
285
286    expectation_group no_expectations;
287    TEST_EXPECTATION(all().ofgroup(no_expectations));
288    TEST_EXPECTATION(none().ofgroup(no_expectations));
289
290    expectation_group fulfilled_expectation  (that(1).is_equal_to(1));
291    expectation_group unfulfilled_expectation(that(1).is_equal_to(0));
292    expectation_group some_fulfilled_expectations(that(1).is_equal_to(0), that(1).is_equal_to(1));
293
294    TEST_EXPECTATION(all().ofgroup(fulfilled_expectation));
295    TEST_EXPECTATION(none().ofgroup(unfulfilled_expectation));
296
297    TEST_EXPECT(none().ofgroup(fulfilled_expectation).unfulfilled());
298    TEST_EXPECT(all().ofgroup(unfulfilled_expectation).unfulfilled());
299   
300    TEST_EXPECT(all().ofgroup(some_fulfilled_expectations).unfulfilled());
301    TEST_EXPECT(none().ofgroup(some_fulfilled_expectations).unfulfilled());
302}
303
304void TEST_replace_old_TEST_EXPECTS_by_expectations() {
305    // test various string-types are matchable (w/o casts)
306    {
307        const char *car_ccp = "Alfa";
308        char       *car_cp  = strdup("Alfa");
309        string      car_str("Alfa");
310
311        TEST_EXPECT_EQUAL(car_ccp, "Alfa");
312        TEST_EXPECT_EQUAL(car_cp, "Alfa");
313        TEST_EXPECT_EQUAL(car_str, "Alfa");
314
315        TEST_EXPECT_EQUAL("Alfa", car_ccp);
316        TEST_EXPECT_EQUAL("Alfa", car_cp);
317        TEST_EXPECT_EQUAL("Alfa", car_str);
318
319        TEST_EXPECT_EQUAL(car_cp, car_ccp);
320        TEST_EXPECT_EQUAL(car_cp, car_str);
321        TEST_EXPECT_EQUAL(car_ccp, car_cp);
322        TEST_EXPECT_EQUAL(car_ccp, car_str);
323        TEST_EXPECT_EQUAL(car_str, car_cp);
324        TEST_EXPECT_EQUAL(car_str, car_ccp);
325
326        char *null = NULL;
327        TEST_EXPECT_NULL((void*)NULL);
328        TEST_EXPECT_NULL(null);
329
330        TEST_EXPECT_CONTAINS(car_ccp, "lf");
331        TEST_EXPECT_CONTAINS(car_cp, "fa");
332        TEST_EXPECT_CONTAINS(car_str, "Al");
333
334        free(car_cp);
335    }
336
337    // test various numeric types are matchable
338
339    {
340        short unsigned su = 7;
341        short          s  = -su;
342
343        unsigned iu = su;
344        int      i  = -iu;
345
346        long unsigned lu = (long unsigned)INT_MAX+3;
347        long          l  = -lu;
348
349        float  f = s;
350        double d = i;
351
352        TEST_EXPECT_EQUAL(s, -7);
353        TEST_EXPECT_EQUAL(i, -7);
354
355        TEST_EXPECT_EQUAL(su, 7);  TEST_EXPECT_EQUAL(iu, 7);
356        TEST_EXPECT_EQUAL(su, 7U); TEST_EXPECT_EQUAL(iu, 7U);
357        TEST_EXPECT_EQUAL(su, 7L); TEST_EXPECT_EQUAL(iu, 7L);
358
359        TEST_EXPECT_EQUAL(s, -su); TEST_EXPECT_EQUAL(s, -iu);
360        TEST_EXPECT_EQUAL(i, -iu); TEST_EXPECT_EQUAL(i, -su);
361        TEST_EXPECT_EQUAL(l, -lu);
362
363        TEST_EXPECT_EQUAL(f, d);
364        TEST_EXPECT_EQUAL(d, f);
365    }
366
367    TEST_EXPECT_ZERO(7-7);
368}
369
370// --- simulate user_type (which may be defined anywhere) ---
371class user_type {
372    int x, y;
373public:
374    user_type(int X, int Y) : x(X), y(Y) {}
375
376    int get_x() const { return x; }
377    int get_y() const { return y; }
378
379    user_type flipped() const { return user_type(y,x); }
380
381    int quadrant() const {
382        if (x == 0 || y == 0) return 0; // on axis
383        if (y>0) return x<0 ? 2 : 1;
384        return x<0 ? 3 : 4;
385    }
386};
387// --- end of user_type ---
388
389// helpers needed for tests:
390inline bool operator == (const user_type& u1, const user_type& u2) { return u1.get_x() == u2.get_x() && u1.get_y() == u2.get_y(); }
391inline char *val2readable(const user_type& u) { return arb_test::StaticCode::strf("user_type(%i,%i)", u.get_x(), u.get_y()); }
392inline bool in_same_quadrant(const user_type& u1, const user_type& u2) { return u1.quadrant() == u2.quadrant(); }
393
394void TEST_user_type_with_expectations() {
395    user_type ut1(3, 4);
396    user_type ut12(4, 4);
397    user_type ut2(-4, 4);
398    user_type ut3(-4, -8);
399    user_type ut4(4, -8);
400
401    TEST_EXPECTATION(that(ut1).does_differ_from(ut12));
402    TEST_EXPECTATION(that(ut12).is_equal_to(ut12.flipped()));
403    TEST_EXPECTATION(that(ut1).does_differ_from(ut1.flipped()));
404
405    TEST_EXPECTATION(that(ut1).fulfills(in_same_quadrant, ut12));
406    TEST_EXPECTATION(none().of(that(ut1).fulfills(in_same_quadrant, ut2),
407                          that(ut2).fulfills(in_same_quadrant, ut3),
408                          that(ut3).fulfills(in_same_quadrant, ut4)));
409}
410TEST_PUBLISH(TEST_user_type_with_expectations);
411
412void TEST_similarity() {
413    double d1      = 0.7531;
414    double epsilon = 0.00001;
415    double d2      = d1-epsilon*0.6;
416    double d3      = d1+epsilon*0.6;
417
418    TEST_EXPECTATION(that(d1).fulfills(epsilon_similar(epsilon), d2));
419    TEST_EXPECTATION(that(d1).fulfills(epsilon_similar(epsilon), d3));
420    TEST_EXPECTATION(that(d2).contradicts(epsilon_similar(epsilon), d3));
421
422    TEST_EXPECT_SIMILAR(d1, d2, epsilon);
423    TEST_EXPECT_SIMILAR(d1, d3, epsilon);
424}
425
426void TEST_less_equal() {
427    int x = 7;
428    int y = 8;
429    int z = 9;
430
431    // less/more etc
432
433    TEST_EXPECTATION(that(x).is_less_than(y));
434    TEST_EXPECTATION(that(x).is_less_or_equal(y));
435    TEST_EXPECTATION(that(x).is_less_or_equal(x));
436   
437    TEST_EXPECTATION(that(y).is_more_than(x));
438    TEST_EXPECTATION(that(y).is_more_or_equal(x));
439    TEST_EXPECTATION(that(y).is_more_or_equal(y));
440
441    TEST_EXPECT_LESS_EQUAL(x, y);
442    TEST_EXPECT_LESS_EQUAL(x, x);
443    TEST_EXPECT_LESS(x, y);
444    TEST_EXPECT_IN_RANGE(y, x, z);
445}
446TEST_PUBLISH(TEST_less_equal);
447
448enum MyEnum {
449    MY_UNKNOWN,
450    MY_RNA,
451    MY_DNA,
452    MY_AA,
453};
454
455void TEST_MyEnum_loop() {
456    int loops_performed = 0;
457    const char * const db_name[]=  { NULL, "TEST_trees.arb", "TEST_realign.arb", "TEST_realign.arb", NULL };
458    for (int iat = MY_RNA; iat<=MY_AA; ++iat) {
459        MyEnum at = MyEnum(iat);
460        TEST_EXPECT(at>=1 && at<=3);
461        fprintf(stderr, "at=%i db_name[%i]='%s'\n", at, at, db_name[at]);
462        TEST_REJECT_NULL(db_name[at]);
463        loops_performed++;
464    }
465    TEST_EXPECT_EQUAL(loops_performed, 3);
466}
467
468TEST_PUBLISH(TEST_MyEnum_loop);
469
470#endif // UNIT_TESTS
471
472// --------------------------------------------------------------------------------
473
474
Note: See TracBrowser for help on using the repository browser.