source: branches/profile/TOOLS/arb_test.cxx

Last change on this file was 13641, checked in by westram, 9 years ago
  • merge [13018] from 'trunk' into 'profile' (to fix unittests in gcc491+NDEBUG)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : arb_test.cxx                                      //
4//   Purpose   : unit tester for tools                             //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in February 2011  //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#include <arbdbt.h>
13#include <arb_defs.h>
14#include <arb_sleep.h>
15#include <arb_diff.h>
16#include <unistd.h>
17
18int ARB_main(int , char *[]) {
19    fputs("don't call us\n", stderr);
20    return EXIT_SUCCESS;
21}
22
23// --------------------------------------------------------------------------------
24
25#ifdef UNIT_TESTS
26#include <arb_file.h>
27#include <test_unit.h>
28#include <ut_valgrinded.h>
29
30// --------------------------------------------------------------------------------
31
32
33inline void make_valgrinded_call_from_pipe(char *&command) {
34    using namespace utvg;
35    static valgrind_info valgrind;
36    if (valgrind.wanted) {
37        char *pipeSym = strchr(command, '|');
38        if (pipeSym) {
39            char *left  = GB_strpartdup(command, pipeSym-1);
40            char *right = strdup(pipeSym+1);
41
42            make_valgrinded_call(left);
43            make_valgrinded_call_from_pipe(right);
44
45            freeset(command, GBS_global_string_copy("%s | %s", left, right));
46
47            free(right);
48            free(left);
49        }
50        else {
51            make_valgrinded_call(command);
52        }
53    }
54}
55
56inline GB_ERROR valgrinded_system(const char *cmdline) {
57    char *cmddup = strdup(cmdline);
58    make_valgrinded_call_from_pipe(cmddup);
59
60    GB_ERROR error = GBK_system(cmddup);
61    free(cmddup);
62    return error;
63}
64
65#define RUN_TOOL(cmdline)                valgrinded_system(cmdline)
66#define RUN_TOOL_NEVER_VALGRIND(cmdline) GBK_system(cmdline)
67
68#define TEST_RUN_TOOL(cmdline)                TEST_EXPECT_NO_ERROR(RUN_TOOL(cmdline))
69#define TEST_RUN_TOOL_NEVER_VALGRIND(cmdline) TEST_EXPECT_NO_ERROR(RUN_TOOL_NEVER_VALGRIND(cmdline))
70
71void TEST_SLOW_ascii_2_bin_2_ascii() {
72    const char *ascii_ORG  = "TEST_loadsave_ascii.arb";
73    const char *ascii      = "bin2ascii.arb";
74    const char *binary     = "ascii2bin.arb";
75    const char *binary_2ND = "ascii2bin2.arb";
76
77    // test conversion file -> file
78    TEST_RUN_TOOL(GBS_global_string("arb_2_bin   %s %s", ascii_ORG, binary));
79    TEST_RUN_TOOL(GBS_global_string("arb_2_ascii %s %s", binary, ascii));
80
81    TEST_EXPECT_FILES_EQUAL(ascii, ascii_ORG);
82
83    // test conversion (bin->ascii->bin) via stream (this tests 'arb_repair')
84    TEST_RUN_TOOL(GBS_global_string("arb_2_ascii %s - | arb_2_bin - %s", binary, binary_2ND));
85
86    // TEST_EXPECT_FILES_EQUAL(binary, binary_2ND); // can't compare binary files (they contain undefined bytes)
87
88    // instead convert back to ascii and compare result with original
89    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(ascii));
90    TEST_RUN_TOOL(GBS_global_string("arb_2_ascii %s %s", binary_2ND, ascii));
91    TEST_EXPECT_FILES_EQUAL(ascii, ascii_ORG);
92
93    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(ascii));
94    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(binary));
95    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(binary_2ND));
96    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink("ascii2bin.ARF"));
97    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink("ascii2bin2.ARF"));
98}
99
100void TEST_arb_primer() {
101    const char *primer_db       = "TEST_nuc.arb";
102    const char *primer_stdin    = "tools/arb_primer.in";
103    const char *primer_out      = "tools/arb_primer.out";
104    const char *primer_expected = "tools/arb_primer_expected.out";
105
106    TEST_RUN_TOOL(GBS_global_string("arb_primer %s < %s", primer_db, primer_stdin));
107    TEST_EXPECT_FILES_EQUAL(primer_out, primer_expected);
108    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(primer_out));
109}
110
111static GB_ERROR removeVaryingDateFromTreeRemarks(const char *dbname) {
112    GB_ERROR  error     = NULL;
113    GB_shell  shell;
114    GBDATA   *gb_main   = GB_open(dbname, "rw");
115    if (!gb_main) error = GB_await_error();
116    else {
117        {
118            GB_transaction ta(gb_main);
119
120            GBDATA     *gb_tree_data    = GBT_get_tree_data(gb_main);
121            const char *truncate_after  = "\nunittest-tree\n";
122            size_t      truncate_offset = strlen(truncate_after);
123
124            if (!gb_tree_data) error = GB_await_error();
125            else {
126                for (GBDATA *gb_tree = GB_child(gb_tree_data);
127                     gb_tree && !error;
128                     gb_tree = GB_nextChild(gb_tree))
129                {
130                    GBDATA *gb_remark = GB_entry(gb_tree, "remark");
131                    if (!gb_remark) {
132                        error = "could not find 'remark' entry";
133                    }
134                    else {
135                        char *remark = GB_read_string(gb_remark);
136                        char *found  = strstr(remark, truncate_after);
137
138                        if (found) {
139                            strcpy(found+truncate_offset, "<date removed for testing>");
140                            error                  = GB_write_string(gb_remark, remark);
141                        }
142                        free(remark);
143                    }
144                }
145            }
146
147            ta.close(error);
148        }
149        if (!error) error = GB_save_as(gb_main, dbname, "a");
150        GB_close(gb_main);
151    }
152    return error;
153}
154
155// #define TEST_AUTO_UPDATE_TREE // uncomment to auto-update expected tree
156
157void TEST_SLOW_arb_read_tree() {
158    struct {
159        const char *basename;
160        const char *extraArgs;
161    }
162    run[] = {
163        { "newick",           "" },
164        { "newick_sq",        "-commentFromFile general/text.input" },
165        { "newick_dq",        "-scale 0.5" },
166        { "newick_group",     "-scale 10 -consense 10" },
167        { "newick_len",       "" },
168        { "newick_len_group", "" },
169    };
170
171    const char *dbin       = "min_ascii.arb";
172    const char *dbout      = "tools/read_tree_out.arb";
173    const char *dbexpected = "tools/read_tree_out_expected.arb";
174
175    for (size_t b = 0; b<ARRAY_ELEMS(run); ++b) {
176        const char *basename  = run[b].basename;
177        const char *extraArgs = run[b].extraArgs;
178        char       *treefile  = GBS_global_string_copy("tools/%s.tree", basename);
179        char       *treename  = GBS_global_string_copy("tree_%s", basename);
180
181        TEST_RUN_TOOL(GBS_global_string("arb_read_tree -db %s %s %s %s \"test %s\" %s",
182                                                   dbin, dbout, treename, treefile, basename, extraArgs));
183
184        dbin = dbout; // use out-db from previous loop ( = write all trees into one db)
185
186        free(treename);
187        free(treefile);
188    }
189
190    TEST_EXPECT_NO_ERROR(removeVaryingDateFromTreeRemarks(dbout));
191#if defined(TEST_AUTO_UPDATE_TREE)
192    system(GBS_global_string("cp %s %s", dbout, dbexpected));
193#else // !defined(TEST_AUTO_UPDATE_TREE)
194    TEST_EXPECT_TEXTFILES_EQUAL(dbexpected, dbout);
195#endif
196    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(dbout));
197}
198
199#define TEST_ARB_REPLACE(infile,expected,args) do {                     \
200        char *tmpfile = GBS_global_string_copy("%s.tmp", expected);     \
201        TEST_RUN_TOOL_NEVER_VALGRIND(GBS_global_string("cp %s %s", infile, tmpfile));  \
202        TEST_RUN_TOOL(GBS_global_string("arb_replace %s %s", args, tmpfile)); \
203        TEST_EXPECT_TEXTFILES_EQUAL(tmpfile, expected);                 \
204        TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(tmpfile));             \
205        free(tmpfile);                                                  \
206    } while(0)
207
208void TEST_arb_replace() {
209    const char *infile = "tools/arb_replace.in";
210    const char *file1  = "tools/arb_replace_1.out";
211    const char *file2  = "tools/arb_replace_2.out";
212
213    TEST_ARB_REPLACE(infile, "tools/arb_replace_1.out", "'gene=GONE'");
214    TEST_ARB_REPLACE(file1,  infile,                    "-l 'GONE=gene'");
215    TEST_ARB_REPLACE(file1,  file2,                     "-L 'GONE=gene:\"*\"=( * )'");
216}
217
218// --------------------------------------------------------------------------------
219
220#include "command_output.h"
221
222void TEST_arb_message() {
223    TEST_STDERR_EQUALS("arb_message \"this is the test message\"",
224                       "arb_message: this is the test message\n");
225}
226
227void TEST_SLOW_arb_probe() {
228    // test called here currently are duplicating the tests in
229    // arb_probe.cxx@TEST_SLOW_match_probe
230    // and arb_probe.cxx@TEST_SLOW_design_probe
231    //
232    // Here test of functionality is secondary.
233    // The primary goal here is to test calling the tools (i.e. arb_probe)
234   
235    TEST_SETUP_GLOBAL_ENVIRONMENT("ptserver");
236    TEST_STDOUT_EQUALS("arb_probe"
237                       " serverid=-666"
238                       " matchsequence=UAUCGGAGAGUUUGA",
239
240                       /* ---- */ "    name---- fullname mis N_mis wmis pos ecoli rev          'UAUCGGAGAGUUUGA'\1"
241                       "BcSSSS00\1" "  BcSSSS00            0     0  0.0   3     2 0   .......UU-===============-UCAAGUCGA\1"
242        );
243
244    TEST_STDOUT_EQUALS("arb_probe"
245                       " serverid=-666"
246                       " designnames=ClnCorin#CltBotul#CPPParap#ClfPerfr"
247                       " designmintargets=100",
248
249                       "Probe design parameters:\n"
250                       "Length of probe    18\n"
251                       "Temperature        [ 0.0 -400.0]\n"
252                       "GC-content         [30.0 - 80.0]\n"
253                       "E.Coli position    [any]\n"
254                       "Max. nongroup hits 0\n"
255                       "Min. group hits    100% (max. rejected coverage: 75%)\n"
256                       "Target             le apos ecol qual grps   G+C temp     Probe sequence | Decrease T by n*.3C -> probe matches n non group species\n"
257                       "CGAAAGGAAGAUUAAUAC 18 A=94   82   77    4  33.3 48.0 GUAUUAAUCUUCCUUUCG | - - - - - - - - - - - - - - - - - - - -\n"
258                       "GAAAGGAAGAUUAAUACC 18 A+ 1   83   77    4  33.3 48.0 GGUAUUAAUCUUCCUUUC | - - - - - - - - - - - - - - - - - - - -\n"
259                       "UCAAGUCGAGCGAUGAAG 18 B=18   17   61    4  50.0 54.0 CUUCAUCGCUCGACUUGA | - - - - - - - - - - - - - - - 2 2 2 2 2\n"
260                       "AUCAAGUCGAGCGAUGAA 18 B- 1   16   45    4  44.4 52.0 UUCAUCGCUCGACUUGAU | - - - - - - - - - - - 2 2 2 2 2 2 2 2 2\n"
261                       );
262}
263
264#define IN_DB     "tools/dnarates.arb"
265#define OUT_DB    "tools/dnarates_result.arb"
266#define WANTED_DB "tools/dnarates_expected.arb"
267
268// #define TEST_AUTO_UPDATE_SAI // uncomment to auto-update expected SAI
269
270void TEST_SLOW_arb_dna_rates() {
271    TEST_STDOUT_CONTAINS("arb_dnarates tools/dnarates.inp " IN_DB " " OUT_DB, "\nWriting 'POS_VAR_BY_ML_1'\n");
272
273#if defined(TEST_AUTO_UPDATE_SAI)
274    TEST_COPY_FILE(OUT_DB, WANTED_DB);
275#else // !defined(TEST_AUTO_UPDATE_SAI)
276    TEST_EXPECT_TEXTFILES_EQUAL(WANTED_DB, OUT_DB);
277#endif
278    TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(OUT_DB));
279}
280
281#define RATES_DB "tools/exportrates.arb"
282
283void TEST_arb_export_rates() {
284    // Note: just testing against regression here.
285    // Since the output is quite longish, we just test the checksums of the results.
286    //
287    // If one of the checksums changes unexpectedly and you want to see more details about the change,
288    // - go back to a revision with a correct checksum,
289    // - add passing TEST_OUTPUT_EQUALS for broken command and
290    // - move that test to broken revision.
291
292    TEST_OUTPUT_HAS_CHECKSUM("arb_export_rates -d " RATES_DB " POS_VAR_BY_PARSIMONY", 0xc75a5fad);
293    TEST_OUTPUT_HAS_CHECKSUM("arb_export_rates -d " RATES_DB " -r POS_VAR_BY_PARSIMONY", 0xd69fb01e);
294    TEST_OUTPUT_HAS_CHECKSUM("arb_export_rates -d " RATES_DB " -r \"\"", 0xad0461ce);
295}
296
297#define TREE_DB "tools/tree.arb"
298
299void TEST_arb_export_tree() {
300    TEST_STDOUT_EQUALS("arb_export_tree tree_mini " TREE_DB,
301                       "((( 'VibFurni' :0.02952, 'VibVulni' :0.01880):0.04015, 'VibChole' :0.03760):1.00000,( 'AcnPleur' :0.12011, 'PrtVulga' :0.06756):1.00000, 'HlmHalod' :1.00000);\n");
302    TEST_STDOUT_EQUALS("arb_export_tree --bifurcated tree_mini " TREE_DB,
303                       "(((( 'VibFurni' :0.02952, 'VibVulni' :0.01880):0.04015, 'VibChole' :0.03760):0.04610,( 'AcnPleur' :0.12011, 'PrtVulga' :0.06756):0.01732):0.07176, 'HlmHalod' :0.12399)'inner';\n");
304    TEST_STDOUT_EQUALS("arb_export_tree --doublequotes tree_mini " TREE_DB,
305                       "((( \"VibFurni\" :0.02952, \"VibVulni\" :0.01880):0.04015, \"VibChole\" :0.03760):1.00000,( \"AcnPleur\" :0.12011, \"PrtVulga\" :0.06756):1.00000, \"HlmHalod\" :1.00000);\n");
306
307    TEST_STDOUT_EQUALS("arb_export_tree --nobranchlens tree_mini " TREE_DB,
308                       "((( 'VibFurni'  'VibVulni' ) 'VibChole' ),( 'AcnPleur'  'PrtVulga' ), 'HlmHalod' );\n");
309    TEST_EXPECT__BROKEN(0); // the test above returns a wrong result (commas are missing)
310
311    TEST_OUTPUT_EQUALS("arb_export_tree \"\" " TREE_DB,
312                       ";\n",                                                                    // shall export an empty newick tree
313                       "");                                                                      // without error!
314    TEST_OUTPUT_EQUALS("arb_export_tree tree_nosuch " TREE_DB,
315                       ";\n",                                                                    // shall export an empty newick tree
316                       "arb_export_tree from '" TREE_DB "': ARB ERROR: Failed to read tree 'tree_nosuch' (Reason: tree not found)\n"); // with error!
317}
318TEST_PUBLISH(TEST_arb_export_tree);
319
320static char *notification_result = NULL;
321static void test_notification_cb(const char *message, void *cd) {
322    const char *cds     = (const char *)cd;
323    notification_result = GBS_global_string_copy("message='%s' cd='%s'", message, cds);
324}
325
326#define INIT_NOTIFICATION                                                                       \
327    GB_shell shell;                                                                             \
328    GBDATA *gb_main = GBT_open("nosuch.arb", "crw");                                            \
329    const char *cd  = "some argument";                                                          \
330    char *cmd = GB_generate_notification(gb_main, test_notification_cb, "the note", (void*)cd)
331
332#define EXIT_NOTIFICATION       \
333    GB_close(gb_main);          \
334    free(cmd)
335   
336#define TEST_DBSERVER_OPEN(gbmain) TEST_EXPECT_NO_ERROR(GBCMS_open(":", 0, gbmain))
337#define TEST_DBSERVER_SERVE_UNTIL(gbmain, cond) do {                    \
338        bool success            = GBCMS_accept_calls(gb_main, false);   \
339        while (success) success = GBCMS_accept_calls(gb_main, true);    \
340        GB_sleep(10, MS);                                               \
341    } while(!(cond))
342
343#define TEST_DBSERVER_CLOSE(gbmain) GBCMS_shutdown(gb_main)
344
345void TEST_close_with_pending_notification() {
346    INIT_NOTIFICATION;
347    EXIT_NOTIFICATION;
348}
349void TEST_close_after_pending_notification_removed() {
350    INIT_NOTIFICATION;
351    TEST_EXPECT_NO_ERROR(GB_remove_last_notification(gb_main));
352    EXIT_NOTIFICATION;
353}
354void TEST_arb_notify() {
355    INIT_NOTIFICATION;
356
357    TEST_DBSERVER_OPEN(gb_main);
358
359    TEST_EXPECT_NULL(notification_result);
360    TEST_EXPECT_NO_ERROR(GBK_system(GBS_global_string("%s &", cmd))); // async call to arb_notify
361
362    TEST_DBSERVER_SERVE_UNTIL(gb_main, notification_result);
363    TEST_DBSERVER_CLOSE(gb_main);
364
365    TEST_EXPECT_EQUAL(notification_result, "message='the note' cd='some argument'");
366    freenull(notification_result);
367
368    EXIT_NOTIFICATION;
369}
370
371#endif // UNIT_TESTS
372
Note: See TracBrowser for help on using the repository browser.