1 /* test/merge/test_trans_tbl_init.c -- merge test harness.
2
3 Copyright (C) 2013-2016, 2019 Genome Research Ltd.
4
5 Author: Martin O. Pollard <mp15@sanger.ac.uk>
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE. */
24
25 #include <config.h>
26
27 #include "../../bam_sort.c"
28 #include <assert.h>
29 #include <regex.h>
30 #include <inttypes.h>
31
32 typedef struct refseq_info {
33 const char *name;
34 uint32_t len;
35 } refseq_info_t;
36
dump_header(sam_hdr_t * hdr)37 void dump_header(sam_hdr_t* hdr) {
38 printf("->n_targets:(%d)\n", sam_hdr_nref(hdr));
39 int i;
40 for (i = 0; i < sam_hdr_nref(hdr); ++i) {
41 printf("->target_name[%d]:(%s)\n", i, sam_hdr_tid2name(hdr, i));
42 printf("->target_len[%d]:(%"PRId64")\n", i, (int64_t) sam_hdr_tid2len(hdr, i));
43 }
44
45 printf("->text:(");
46 fwrite((void*)hdr->text, (size_t) hdr->l_text, 1, stdout);
47 printf(")\n");
48 }
49
populate_merged_header(sam_hdr_t * hdr,merged_header_t * merged_hdr)50 static int populate_merged_header(sam_hdr_t *hdr, merged_header_t *merged_hdr) {
51 trans_tbl_t dummy;
52 int res;
53 res = trans_tbl_init(merged_hdr, hdr, &dummy, 0, 0, 1, NULL);
54 trans_tbl_destroy(&dummy);
55 return res;
56 }
57
58 /*
59 * Populate merged_hdr with data from bam0_header_text and bam0_refseqs.
60 * Return sam_hdr_t based on the content in bam1_header_text and bam1_refseqs.
61 */
62
setup_test(const char * bam0_header_text,const refseq_info_t * bam0_refseqs,int32_t bam0_n_refseqs,const char * bam1_header_text,const refseq_info_t * bam1_refseqs,int32_t bam1_n_refseqs,merged_header_t * merged_hdr)63 sam_hdr_t * setup_test(const char *bam0_header_text,
64 const refseq_info_t *bam0_refseqs,
65 int32_t bam0_n_refseqs,
66 const char *bam1_header_text,
67 const refseq_info_t *bam1_refseqs,
68 int32_t bam1_n_refseqs,
69 merged_header_t *merged_hdr) {
70 sam_hdr_t* bam0 = NULL;
71 sam_hdr_t* bam1 = NULL;
72
73 bam0 = sam_hdr_init();
74 if (!bam0 || -1 == sam_hdr_add_lines(bam0, bam0_header_text, strlen(bam0_header_text)))
75 goto fail;
76
77 if (populate_merged_header(bam0, merged_hdr)) goto fail;
78
79 bam1 = sam_hdr_init();
80 if (!bam1 || -1 == sam_hdr_add_lines(bam1, bam1_header_text, strlen(bam1_header_text)))
81 goto fail;
82
83 sam_hdr_destroy(bam0);
84 return bam1;
85
86 fail:
87 sam_hdr_destroy(bam1);
88 sam_hdr_destroy(bam0);
89 return NULL;
90 }
91
92 #define NELE(x) (sizeof((x)) / sizeof((x)[0]))
93
94 static const char init_text[] =
95 "@HD\tVN:1.4\tSO:unknown\n"
96 "@SQ\tSN:fish\tLN:133\tSP:frog";
97
98 static const refseq_info_t init_refs[1] = {
99 { "fish", 133 }
100 };
101
102 static const char test_1_trans_text[] =
103 "@HD\tVN:1.4\tSO:unknown\n"
104 "@SQ\tSN:fish\tLN:133\n";
105
106 static const refseq_info_t test_1_refs[1] = {
107 { "fish", 133 }
108 };
109
setup_test_1(merged_header_t * merged_hdr)110 sam_hdr_t * setup_test_1(merged_header_t *merged_hdr) {
111 return setup_test(init_text, init_refs, NELE(init_refs),
112 test_1_trans_text, test_1_refs, NELE(test_1_refs),
113 merged_hdr);
114 }
115
check_test_1(sam_hdr_t * translate,sam_hdr_t * out,trans_tbl_t * tbl)116 bool check_test_1(sam_hdr_t* translate, sam_hdr_t* out, trans_tbl_t* tbl) {
117 // Check input is unchanged
118 if (
119 strncmp(test_1_trans_text, sam_hdr_str(translate), sam_hdr_length(translate))
120 || sam_hdr_length(translate) != strlen( test_1_trans_text)
121 || sam_hdr_nref(translate) != 1
122 ) return false;
123
124 // Check output header
125 const char out_regex[] =
126 "^@HD\tVN:1.4\tSO:unknown\n"
127 "@SQ\tSN:fish\tLN:133\tSP:frog\n$";
128
129 regex_t check_regex;
130 regcomp(&check_regex, out_regex, REG_EXTENDED|REG_NOSUB);
131
132 if ( regexec(&check_regex, sam_hdr_str(out), 0, NULL, 0) != 0 || sam_hdr_nref(out) != 1 ) return false;
133
134 regfree(&check_regex);
135
136 // Check output tbl
137 if (tbl[0].n_targets != 1 || tbl[0].tid_trans[0] != 0 || tbl[0].lost_coord_sort) return false;
138
139 return true;
140 }
141
142 static const char test_2_trans_text[] =
143 "@HD\tVN:1.4\tSO:unknown\n"
144 "@SQ\tSN:donkey\tLN:133\n"
145 "@SQ\tSN:fish\tLN:133\n";
146
147 static const refseq_info_t test_2_refs[2] = {
148 { "donkey", 133 },
149 { "fish", 133 }
150 };
151
setup_test_2(merged_header_t * merged_hdr)152 sam_hdr_t * setup_test_2(merged_header_t *merged_hdr) {
153 return setup_test(init_text, init_refs, NELE(init_refs),
154 test_2_trans_text, test_2_refs, NELE(test_2_refs),
155 merged_hdr);
156 }
157
check_test_2(sam_hdr_t * translate,sam_hdr_t * out,trans_tbl_t * tbl)158 bool check_test_2(sam_hdr_t* translate, sam_hdr_t* out, trans_tbl_t* tbl) {
159 // Check input is unchanged
160 if (sam_hdr_length(translate) != strlen(test_2_trans_text)
161 || strncmp(test_2_trans_text, sam_hdr_str(translate), sam_hdr_length(translate))
162 || sam_hdr_nref(translate) != 2
163 ) return false;
164
165 // Check output header
166 const char out_regex[] =
167 "^@HD\tVN:1.4\tSO:unknown\n"
168 "@SQ\tSN:fish\tLN:133\tSP:frog\n"
169 "@SQ\tSN:donkey\tLN:133\n$";
170
171 regex_t check_regex;
172 regcomp(&check_regex, out_regex, REG_EXTENDED|REG_NOSUB);
173
174 if ( regexec(&check_regex, sam_hdr_str(out), 0, NULL, 0) != 0 || sam_hdr_nref(out) != 2 ) return false;
175
176 regfree(&check_regex);
177
178 // Check output tbl
179 if (tbl[0].n_targets != 2 || tbl[0].tid_trans[0] != 1 || tbl[0].tid_trans[1] != 0) return false;
180
181 return true;
182 }
183
184 static const char test_3_trans_text[] =
185 "@HD\tVN:1.4\tSO:unknown\n"
186 "@SQ\tSN:donkey\tLN:133\n"
187 "@SQ\tSN:fish\tLN:133\n"
188 "@RG\tID:fish\tPU:trans\n";
189
190 static const refseq_info_t test_3_refs[2] = {
191 { "donkey", 133 },
192 { "fish", 133 }
193 };
194
setup_test_3(merged_header_t * merged_hdr)195 sam_hdr_t * setup_test_3(merged_header_t *merged_hdr) {
196 return setup_test(init_text, init_refs, NELE(init_refs),
197 test_3_trans_text, test_3_refs, NELE(test_3_refs),
198 merged_hdr);
199 }
200
check_test_3(sam_hdr_t * translate,sam_hdr_t * out,trans_tbl_t * tbl)201 bool check_test_3(sam_hdr_t* translate, sam_hdr_t* out, trans_tbl_t* tbl) {
202 // Check input is unchanged
203 if (
204 strncmp(test_3_trans_text, sam_hdr_str(translate), sam_hdr_length(translate))
205 || sam_hdr_length(translate) != strlen(test_3_trans_text)
206 || sam_hdr_nref(translate) != 2
207 ) return false;
208 return true;
209 }
210
211 static const char test_4_trans_text[] =
212 "@HD\tVN:1.4\tSO:unknown\n"
213 "@SQ\tSN:donkey\tLN:133\n"
214 "@SQ\tSN:fish\tLN:133\n"
215 "@RG\tID:fish\tPU:trans\n";
216
217 static const refseq_info_t test_4_refs[2] = {
218 { "donkey", 133 },
219 { "fish", 133 }
220 };
221
setup_test_4(merged_header_t * merged_hdr)222 sam_hdr_t * setup_test_4(merged_header_t *merged_hdr) {
223 const char* t4_init_text =
224 "@HD\tVN:1.4\tSO:unknown\n"
225 "@SQ\tSN:fish\tLN:133\tSP:frog\n"
226 "@RG\tID:fish\tPU:out\n";
227
228 return setup_test(t4_init_text, init_refs, NELE(init_refs),
229 test_4_trans_text, test_4_refs, NELE(test_4_refs),
230 merged_hdr);
231 }
232
check_test_4(sam_hdr_t * translate,sam_hdr_t * out,trans_tbl_t * tbl)233 bool check_test_4(sam_hdr_t* translate, sam_hdr_t* out, trans_tbl_t* tbl) {
234 // Check input is unchanged
235 if (
236 strncmp(test_4_trans_text, sam_hdr_str(translate), sam_hdr_length(translate))
237 || sam_hdr_length(translate) != strlen(test_4_trans_text)
238 || sam_hdr_nref(translate) != 2
239 ) return false;
240 return true;
241 }
242
243 static const char test_5_trans_text[] =
244 "@HD\tVN:1.4\tSO:unknown\n"
245 "@SQ\tSN:donkey\tLN:133\n"
246 "@SQ\tSN:fish\tLN:133\n"
247 "@RG\tID:fish\tPU:trans\n"
248 "@PG\tXX:dummy\tID:fish\tDS:trans\n"
249 "@PG\tPP:fish\tID:hook\tDS:trans\n";
250
251 static const refseq_info_t test_5_refs[2] = {
252 { "donkey", 133 },
253 { "fish", 133 }
254 };
255
setup_test_5(merged_header_t * merged_hdr)256 sam_hdr_t * setup_test_5(merged_header_t *merged_hdr) {
257 const char* t5_init_text =
258 "@HD\tVN:1.4\tSO:unknown\n"
259 "@SQ\tSN:fish\tLN:133\tSP:frog\n"
260 "@RG\tID:fish\tPU:out\n"
261 "@PG\tXX:dummyx\tID:fish\tDS:out\n"
262 "@PG\tPP:fish\tID:hook\tDS:out\n";
263
264 return setup_test(t5_init_text, init_refs, NELE(init_refs),
265 test_5_trans_text, test_5_refs, NELE(test_5_refs),
266 merged_hdr);
267 }
268
check_test_5(sam_hdr_t * translate,sam_hdr_t * out,trans_tbl_t * tbl)269 bool check_test_5(sam_hdr_t* translate, sam_hdr_t* out, trans_tbl_t* tbl) {
270 // Check input is unchanged
271 if (
272 strncmp(test_5_trans_text, sam_hdr_str(translate), sam_hdr_length(translate))
273 || sam_hdr_length(translate) != strlen(test_5_trans_text)
274 || sam_hdr_nref(translate) != 2
275 ) return false;
276 return true;
277 }
278
279 static const char test_6_trans_text[] =
280 "@HD\tVN:1.4\tSO:unknown\n"
281 "@SQ\tSN:donkey\tLN:133\n"
282 "@SQ\tSN:fish\tLN:133\n"
283 "@RG\tID:fish\tPU:trans\n"
284 "@PG\tXX:dummy\tID:fish\tDS:trans\n"
285 "@PG\tPP:fish\tID:hook\tDS:trans\n";
286
287 static const refseq_info_t test_6_refs[2] = {
288 { "donkey", 133 },
289 { "fish", 133 }
290 };
291
setup_test_6(merged_header_t * merged_hdr)292 sam_hdr_t * setup_test_6(merged_header_t *merged_hdr) {
293 return setup_test(init_text, init_refs, NELE(init_refs),
294 test_6_trans_text, test_6_refs, NELE(test_6_refs),
295 merged_hdr);
296 }
297
check_test_6(sam_hdr_t * translate,sam_hdr_t * out,trans_tbl_t * tbl)298 bool check_test_6(sam_hdr_t* translate, sam_hdr_t* out, trans_tbl_t* tbl) {
299 // Check input is unchanged
300 if (
301 strncmp(test_6_trans_text, sam_hdr_str(translate), sam_hdr_length(translate))
302 || sam_hdr_length(translate) != strlen(test_5_trans_text)
303 || sam_hdr_nref(translate) != 2
304 ) return false;
305 return true;
306 }
307
main(int argc,char ** argv)308 int main(int argc, char**argv)
309 {
310 const int NUM_TESTS = 6;
311 int verbose = 0;
312 int success = 0;
313 int failure = 0;
314 int getopt_char;
315 while ((getopt_char = getopt(argc, argv, "v")) != -1) {
316 switch (getopt_char) {
317 case 'v':
318 ++verbose;
319 break;
320 default:
321 break;
322 }
323 }
324
325 // Set the seed to a fixed value so that calls to lrand48 within functions return predictable values
326 const long GIMMICK_SEED = 0x1234330e;
327 hts_srand48(GIMMICK_SEED);
328
329 sam_hdr_t* out;
330 sam_hdr_t* translate;
331
332 if (verbose) printf("BEGIN test 1\n");
333 // setup
334 trans_tbl_t tbl_1;
335 merged_header_t *merged_hdr = init_merged_header();
336 translate = setup_test_1(merged_hdr);
337 assert(translate);
338 // test
339 if (verbose > 1) {
340 printf("translate\n");
341 dump_header(translate);
342 }
343 if (verbose) printf("RUN test 1\n");
344 trans_tbl_init(merged_hdr, translate, &tbl_1, false, false, true, NULL);
345 finish_merged_header(merged_hdr);
346 out = merged_hdr->hdr;
347 free_merged_header(merged_hdr);
348 if (verbose) printf("END RUN test 1\n");
349 if (verbose > 1) {
350 printf("translate\n");
351 dump_header(translate);
352 printf("out\n");
353 dump_header(out);
354 }
355 if (check_test_1(translate, out, &tbl_1)) {
356 if (verbose) printf("Test 1 : PASS\n");
357 ++success;
358 } else {
359 if (verbose) printf("Test 1 : FAIL\n");
360 fprintf(stderr, "Test 1 : FAIL\n");
361 ++failure;
362 }
363 // teardown
364 sam_hdr_destroy(translate);
365 sam_hdr_destroy(out);
366 trans_tbl_destroy(&tbl_1);
367 if (verbose) printf("END test 1\n");
368
369 // test
370 if (verbose) printf("BEGIN test 2\n");
371 // reinit
372 trans_tbl_t tbl_2;
373
374 merged_hdr = init_merged_header();
375 translate = setup_test_2(merged_hdr);
376 assert(translate);
377 if (verbose > 1) {
378 printf("translate\n");
379 dump_header(translate);
380 }
381 if (verbose) printf("RUN test 2\n");
382 trans_tbl_init(merged_hdr, translate, &tbl_2, false, false, true, NULL);
383 finish_merged_header(merged_hdr);
384 out = merged_hdr->hdr;
385 free_merged_header(merged_hdr);
386 if (verbose) printf("END RUN test 2\n");
387 if (verbose > 1) {
388 printf("translate\n");
389 dump_header(translate);
390 printf("out\n");
391 dump_header(out);
392 }
393 if (check_test_2(translate, out, &tbl_2)) {
394 if (verbose) printf("Test 2 : PASS\n");
395 ++success;
396 } else {
397 if (verbose) printf("Test 2 : FAIL\n");
398 fprintf(stderr, "Test 2 : FAIL\n");
399 ++failure;
400 }
401 // teardown
402 sam_hdr_destroy(translate);
403 sam_hdr_destroy(out);
404 trans_tbl_destroy(&tbl_2);
405 if (verbose) printf("END test 2\n");
406
407 // test
408 if (verbose) printf("BEGIN test 3\n");
409 // reinit
410 trans_tbl_t tbl_3;
411 merged_hdr = init_merged_header();
412 translate = setup_test_3(merged_hdr);
413 assert(translate);
414 if (verbose > 1) {
415 printf("translate\n");
416 dump_header(translate);
417 }
418 if (verbose) printf("RUN test 3\n");
419 trans_tbl_init(merged_hdr, translate, &tbl_3, false, false, true, NULL);
420 finish_merged_header(merged_hdr);
421 out = merged_hdr->hdr;
422 free_merged_header(merged_hdr);
423 if (verbose) printf("END RUN test 3\n");
424 if (verbose > 1) {
425 printf("translate\n");
426 dump_header(translate);
427 printf("out\n");
428 dump_header(out);
429 }
430 if (check_test_3(translate, out, &tbl_3)) {
431 if (verbose) printf("Test 3 : PASS\n");
432 ++success;
433 } else {
434 if (verbose) printf("Test 3 : FAIL\n");
435 fprintf(stderr, "Test 3 : FAIL\n");
436 ++failure;
437 }
438 // teardown
439 sam_hdr_destroy(translate);
440 sam_hdr_destroy(out);
441 trans_tbl_destroy(&tbl_3);
442 if (verbose) printf("END test 3\n");
443
444 // test
445 if (verbose) printf("BEGIN test 4\n");
446 // reinit
447 trans_tbl_t tbl_4;
448 merged_hdr = init_merged_header();
449 translate = setup_test_4(merged_hdr);
450 assert(translate);
451 if (verbose > 1) {
452 printf("translate\n");
453 dump_header(translate);
454 }
455 if (verbose) printf("RUN test 4\n");
456 trans_tbl_init(merged_hdr, translate, &tbl_4, false, false, true, NULL);
457 finish_merged_header(merged_hdr);
458 out = merged_hdr->hdr;
459 free_merged_header(merged_hdr);
460 if (verbose) printf("END RUN test 4\n");
461 if (verbose > 1) {
462 printf("translate\n");
463 dump_header(translate);
464 printf("out\n");
465 dump_header(out);
466 }
467 if (check_test_4(translate, out, &tbl_4)) {
468 if (verbose) printf("Test 4 : PASS\n");
469 ++success;
470 } else {
471 if (verbose) printf("Test 4 : FAIL\n");
472 fprintf(stderr, "Test 4 : FAIL\n");
473 ++failure;
474 }
475 // teardown
476 sam_hdr_destroy(translate);
477 sam_hdr_destroy(out);
478 trans_tbl_destroy(&tbl_4);
479 if (verbose) printf("END test 4\n");
480
481 // test
482 if (verbose) printf("BEGIN test 5\n");
483 // reinit
484 trans_tbl_t tbl_5;
485 merged_hdr = init_merged_header();
486 translate = setup_test_5(merged_hdr);
487 assert(translate);
488 if (verbose > 1) {
489
490 printf("translate\n");
491 dump_header(translate);
492 }
493 if (verbose) printf("RUN test 5\n");
494 trans_tbl_init(merged_hdr, translate, &tbl_5, false, false, true, NULL);
495 finish_merged_header(merged_hdr);
496 out = merged_hdr->hdr;
497 free_merged_header(merged_hdr);
498 if (verbose) printf("END RUN test 5\n");
499 if (verbose > 1) {
500 printf("translate\n");
501 dump_header(translate);
502 printf("out\n");
503 dump_header(out);
504 }
505 if (check_test_5(translate, out, &tbl_5)) {
506 if (verbose) printf("Test 5 : PASS\n");
507 ++success;
508 } else {
509 if (verbose) printf("Test 5 : FAIL\n");
510 fprintf(stderr, "Test 5 : FAIL\n");
511 ++failure;
512 }
513 // teardown
514 sam_hdr_destroy(translate);
515 sam_hdr_destroy(out);
516 trans_tbl_destroy(&tbl_5);
517 if (verbose) printf("END test 5\n");
518
519 // test
520 if (verbose) printf("BEGIN test 6\n");
521 // reinit
522 trans_tbl_t tbl_6;
523 merged_hdr = init_merged_header();
524 translate = setup_test_6(merged_hdr);
525 assert(translate);
526 if (verbose > 1) {
527 printf("translate\n");
528 dump_header(translate);
529 }
530 if (verbose) printf("RUN test 6\n");
531 trans_tbl_init(merged_hdr, translate, &tbl_6, false, false, true, "filename");
532 finish_merged_header(merged_hdr);
533 out = merged_hdr->hdr;
534 free_merged_header(merged_hdr);
535 if (verbose) printf("END RUN test 6\n");
536 if (verbose > 1) {
537 printf("translate\n");
538 dump_header(translate);
539 printf("out\n");
540 dump_header(out);
541 }
542 if (check_test_6(translate, out, &tbl_6)) {
543 if (verbose) printf("Test 6 : PASS\n");
544 ++success;
545 } else {
546 if (verbose) printf("Test 6 : FAIL\n");
547 fprintf(stderr, "Test 6 : FAIL\n");
548 ++failure;
549 }
550 // teardown
551 sam_hdr_destroy(translate);
552 sam_hdr_destroy(out);
553 trans_tbl_destroy(&tbl_6);
554 if (verbose) printf("END test 6\n");
555
556 if (success == NUM_TESTS) {
557 return 0;
558 } else {
559 fprintf(stderr, "%d failures %d successes\n", failure, success);
560 return 1;
561 }
562 }
563