From 5093b36ff675c1cd4479736f9cfdaac74aa107ac Mon Sep 17 00:00:00 2001 From: Enrico Seiler Date: Wed, 6 Nov 2024 15:58:20 +0100 Subject: [PATCH] [TEST] Add testcase --- test/unit/io/sam_file/format_bam_test.cpp | 26 +++++++++ test/unit/io/sam_file/format_sam_test.cpp | 20 ++++++- .../sam_file_format_test_template.hpp | 55 ++++++++++++++++++- 3 files changed, 97 insertions(+), 4 deletions(-) diff --git a/test/unit/io/sam_file/format_bam_test.cpp b/test/unit/io/sam_file/format_bam_test.cpp index e3d436efe3..2d2e731a9c 100644 --- a/test/unit/io/sam_file/format_bam_test.cpp +++ b/test/unit/io/sam_file/format_bam_test.cpp @@ -393,6 +393,32 @@ struct sam_file_read : public sam_file_data '\x14', '\x00', '\x00', '\x00', '\x10', '\x00', '\x00', '\x00', '\x12', '\x00', '\x00', '\x00', '\x10', '\x00', '\x00', '\x00', '\x11', '\x00', '\x00', '\x00', '\x12', '\x48', '\x00', '\x02', '\x02', '\x03', '\x62', '\x48', '\x48', '\x31', '\x41', '\x45', '\x33', '\x30', '\x00'}; + + std::vector issue3299_output{ + {'\x42', '\x41', '\x4d', '\x01', '\x35', '\x00', '\x00', '\x00', '\x40', '\x48', '\x44', '\x09', '\x56', '\x4e', + '\x3a', '\x31', '\x2e', '\x36', '\x0a', '\x40', '\x53', '\x51', '\x09', '\x53', '\x4e', '\x3a', '\x68', '\x65', + '\x6c', '\x6c', '\x6f', '\x09', '\x4c', '\x4e', '\x3a', '\x31', '\x30', '\x30', '\x30', '\x0a', '\x40', '\x53', + '\x51', '\x09', '\x53', '\x4e', '\x3a', '\x77', '\x6f', '\x72', '\x6c', '\x64', '\x09', '\x4c', '\x4e', '\x3a', + '\x32', '\x30', '\x30', '\x30', '\x0a', '\x02', '\x00', '\x00', '\x00', '\x06', '\x00', '\x00', '\x00', '\x68', + '\x65', '\x6c', '\x6c', '\x6f', '\x00', '\xe8', '\x03', '\x00', '\x00', '\x06', '\x00', '\x00', '\x00', '\x77', + '\x6f', '\x72', '\x6c', '\x64', '\x00', '\xd0', '\x07', '\x00', '\x00'}, + {'\x42', '\x41', '\x4d', '\x01', '\x3b', '\x00', '\x00', '\x00', '\x40', '\x48', '\x44', '\x09', '\x56', '\x4e', + '\x3a', '\x31', '\x2e', '\x36', '\x0a', '\x40', '\x53', '\x51', '\x09', '\x53', '\x4e', '\x3a', '\x68', '\x65', + '\x6c', '\x6c', '\x6f', '\x66', '\x6f', '\x6f', '\x09', '\x4c', '\x4e', '\x3a', '\x31', '\x30', '\x30', '\x31', + '\x0a', '\x40', '\x53', '\x51', '\x09', '\x53', '\x4e', '\x3a', '\x77', '\x6f', '\x72', '\x6c', '\x64', '\x66', + '\x6f', '\x6f', '\x09', '\x4c', '\x4e', '\x3a', '\x32', '\x30', '\x30', '\x31', '\x0a', '\x02', '\x00', '\x00', + '\x00', '\x09', '\x00', '\x00', '\x00', '\x68', '\x65', '\x6c', '\x6c', '\x6f', '\x66', '\x6f', '\x6f', '\x00', + '\xe9', '\x03', '\x00', '\x00', '\x09', '\x00', '\x00', '\x00', '\x77', '\x6f', '\x72', '\x6c', '\x64', '\x66', + '\x6f', '\x6f', '\x00', '\xd1', '\x07', '\x00', '\x00'}, + {'\x42', '\x41', '\x4d', '\x01', '\x41', '\x00', '\x00', '\x00', '\x40', '\x48', '\x44', '\x09', '\x56', + '\x4e', '\x3a', '\x31', '\x2e', '\x36', '\x0a', '\x40', '\x53', '\x51', '\x09', '\x53', '\x4e', '\x3a', + '\x68', '\x65', '\x6c', '\x6c', '\x6f', '\x66', '\x6f', '\x6f', '\x66', '\x6f', '\x6f', '\x09', '\x4c', + '\x4e', '\x3a', '\x31', '\x30', '\x30', '\x32', '\x0a', '\x40', '\x53', '\x51', '\x09', '\x53', '\x4e', + '\x3a', '\x77', '\x6f', '\x72', '\x6c', '\x64', '\x66', '\x6f', '\x6f', '\x66', '\x6f', '\x6f', '\x09', + '\x4c', '\x4e', '\x3a', '\x32', '\x30', '\x30', '\x32', '\x0a', '\x02', '\x00', '\x00', '\x00', '\x0c', + '\x00', '\x00', '\x00', '\x68', '\x65', '\x6c', '\x6c', '\x6f', '\x66', '\x6f', '\x6f', '\x66', '\x6f', + '\x6f', '\x00', '\xea', '\x03', '\x00', '\x00', '\x0c', '\x00', '\x00', '\x00', '\x77', '\x6f', '\x72', + '\x6c', '\x64', '\x66', '\x6f', '\x6f', '\x66', '\x6f', '\x6f', '\x00', '\xd2', '\x07', '\x00', '\x00'}}; }; // --------------------------------------------------------------------------------------------------------------------- diff --git a/test/unit/io/sam_file/format_sam_test.cpp b/test/unit/io/sam_file/format_sam_test.cpp index f69cca440e..0c39c904fe 100644 --- a/test/unit/io/sam_file/format_sam_test.cpp +++ b/test/unit/io/sam_file/format_sam_test.cpp @@ -107,6 +107,20 @@ read1 41 * 1 61 1S1M1D1M1I * 0 0 ACGT !##$ std::string wrong_hexadecimal_tag{ R"(@SQ SN:ref LN:150 read1 41 ref 1 61 1S1M1D1M1I = 10 300 ACGT !##$ bH:H:1AE30 +)"}; + + std::vector issue3299_output{ + R"(@HD VN:1.6 +@SQ SN:hello LN:1000 +@SQ SN:world LN:2000 +)", + R"(@HD VN:1.6 +@SQ SN:hellofoo LN:1001 +@SQ SN:worldfoo LN:2001 +)", + R"(@HD VN:1.6 +@SQ SN:hellofoofoo LN:1002 +@SQ SN:worldfoofoo LN:2002 )"}; }; @@ -384,9 +398,9 @@ TEST_F(sam_format, write_different_header) write_header(); ostream.flush(); - EXPECT_EQ( - ostream.str(), - "@HD\tVN:1.6\tSO:coordinate\tSS:query\tGO:reference\n@SQ\tSN:ref\tLN:34\n*\t0\tref\t1\t0\t*\t*\t0\t0\t*\t*\n"); + EXPECT_EQ(ostream.str(), + "@HD\tVN:1.6\tSO:coordinate\tSS:query\tGO:reference\n@SQ\tSN:ref\tLN:34\n*\t0\tref\t1\t0\t*\t*" + "\t0\t0\t*\t*\n"); } TEST_F(sam_format, issue2195) diff --git a/test/unit/io/sam_file/sam_file_format_test_template.hpp b/test/unit/io/sam_file/sam_file_format_test_template.hpp index 6f9b3bc01a..6018b1fda1 100644 --- a/test/unit/io/sam_file/sam_file_format_test_template.hpp +++ b/test/unit/io/sam_file/sam_file_format_test_template.hpp @@ -705,6 +705,58 @@ TYPED_TEST_P(sam_file_write, format_errors) seqan3::format_error); } +TYPED_TEST_P(sam_file_write, issue3299) +{ + using sam_file_output_t = seqan3::sam_file_output::selected_field_ids, + seqan3::type_list, + std::vector>; + std::vector seq_names{"hello", "world"}; + std::vector seq_lengths{1000, 2000}; + + // Issue: Moved-from sam_file_output would try to write header on destruction + { + sam_file_output_t fout1{std::ostringstream{}, seq_names, seq_lengths, TypeParam{}}; + sam_file_output_t fout2{std::move(fout1)}; + } + + // Issue: Header does not own ref_ids: ref_ids outlives sam_file_output + { + std::vector alignment_streams; + auto seq_names_copy = seq_names; + alignment_streams.emplace_back(std::ostringstream{}, seq_names_copy, seq_lengths, TypeParam{}); + // Destructor calls: + // 1) seq_names_copy + // 2) alignment_streams, starting with the one element it holds + } + + // Issue: Header does not own ref_ids: ref_ids may change + size_t const iterations{this->issue3299_output.size()}; + // Order of destruction of vector elements differs between GCC and Clang + std::vector outputs(iterations); + { + std::vector alignment_streams; + for (size_t i = 0; i < iterations; ++i) + { + alignment_streams.emplace_back(outputs[i], seq_names, seq_lengths, TypeParam{}); + + std::ranges::for_each(seq_names, + [](std::string & str) + { + str += "foo"; + }); + std::ranges::for_each(seq_lengths, + [](size_t & len) + { + ++len; + }); + } + } + for (size_t i = 0; i < iterations; ++i) + { + EXPECT_EQ(outputs[i].str(), this->issue3299_output[i]) << "Iteration: " << i; + } +} + REGISTER_TYPED_TEST_SUITE_P(sam_file_read, input_concept, header_sucess, @@ -729,4 +781,5 @@ REGISTER_TYPED_TEST_SUITE_P(sam_file_write, with_header, cigar_vector, special_cases, - format_errors); + format_errors, + issue3299);