From e509abd1267c8c4b66e29c5117e5956d92a2f69b Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 21 Aug 2014 18:25:00 -0400 Subject: [PATCH] TestUtils: add copy/move operation test functions Testing move and copy operations are something we do all the time and it's not always trivial. It includes a lot of boiler plate code. These two template functions take away the boiler plate and test the following aspects of the copy and move operations: * copy and move construction * copy and move assignment * check that self assignment doesn't destroy the object The copy version returns all three copies made to test the functionality. The move version returns the final moved to object. Note that the move function will move from the parameter passed in, so that parameter becomes unusable. fixes #206 --- gamgee/fastq.h | 17 +++- gamgee/indexed_sam_reader.h | 8 +- test/fastq_reader_test.cpp | 24 ++++- test/indexed_sam_reader_test.cpp | 22 +++-- test/interval_test.cpp | 21 ++++- test/sam_header_test.cpp | 16 ++-- test/sam_test.cpp | 153 +++++++++++++++++-------------- test/test_utils.h | 53 +++++++++++ test/variant_header_test.cpp | 15 +++ test/variant_reader_test.cpp | 33 ++----- 10 files changed, 244 insertions(+), 118 deletions(-) create mode 100644 test/test_utils.h diff --git a/gamgee/fastq.h b/gamgee/fastq.h index 230cf6bd4..a5c8e6a9a 100644 --- a/gamgee/fastq.h +++ b/gamgee/fastq.h @@ -27,19 +27,34 @@ class Fastq { m_name {name}, m_comment {comment}, m_sequence{sequence}, m_quals{quals} {} + Fastq(const Fastq&) = default; + Fastq& operator=(const Fastq&) = default; + Fastq(Fastq&&) = default; + Fastq& operator=(Fastq&&) = default; + /** * @brief inequality comparison of all fields in the record * + * @return true if any field differs (string comparison) + */ + bool operator!=(const Fastq& other) const { + return !(*this == other); + } + + /** + * @brief equality comparison of all fields in the record + * * @return true only if every field is the same (string comparison) */ - bool operator!=(const Fastq& other) { + bool operator==(const Fastq& other) const { return m_name == other.m_name && m_comment == other.m_comment && m_sequence == other.m_sequence && m_quals == other.m_quals; } + std::string name() const { return m_name; } std::string comment() const { return m_comment; } std::string sequence() const { return m_sequence; } diff --git a/gamgee/indexed_sam_reader.h b/gamgee/indexed_sam_reader.h index adb54b16b..f3e0991e3 100644 --- a/gamgee/indexed_sam_reader.h +++ b/gamgee/indexed_sam_reader.h @@ -56,10 +56,14 @@ class IndexedSamReader { IndexedSamReader& operator=(IndexedSamReader&& other) = default; /** - * @brief no copy construction/assignment allowed for iterators and readers + * @brief no copy construction/assignment allowed for input iterators and readers */ IndexedSamReader(const IndexedSamReader& other) = delete; - IndexedSamReader& operator=(const IndexedSamReader& other) = delete; + + /** + * @copydoc IndexedSamReader(IndexedSamReader&) + */ + IndexedSamReader& operator=(IndexedSamReader& other) = delete; /** * @brief creates a ITERATOR pointing at the start of the input stream (needed by for-each diff --git a/test/fastq_reader_test.cpp b/test/fastq_reader_test.cpp index 557950a46..b4fb28428 100644 --- a/test/fastq_reader_test.cpp +++ b/test/fastq_reader_test.cpp @@ -1,7 +1,8 @@ -#include "../gamgee/fastq_reader.h" - #include +#include "fastq_reader.h" +#include "test_utils.h" + using namespace std; using namespace gamgee; @@ -45,3 +46,22 @@ BOOST_AUTO_TEST_CASE( read_fastq_vector_too_large ) { BOOST_CHECK_THROW(vector_too_large("testdata/complete_same_seq.fa"), std::runtime_error); } + +BOOST_AUTO_TEST_CASE( fastq_copy_and_move_constructor ) { + auto it = FastqReader{"testdata/complete_same_seq.fa"}.begin(); + auto c0 = *it; + auto copies = check_copy_constructor(c0); + auto c1 = get<0>(copies); + auto c2 = get<1>(copies); + auto c3 = get<2>(copies); + BOOST_CHECK(c0 == c1); + BOOST_CHECK(c0 == c2); + BOOST_CHECK(c0 == c3); + c1.set_name("modified"); + BOOST_CHECK(c1 != c0); + BOOST_CHECK(c1 != c2); + auto m0 = *it; + auto m1 = check_move_constructor(m0); + auto m2 = *it; + BOOST_CHECK(m1 == m2); +} diff --git a/test/indexed_sam_reader_test.cpp b/test/indexed_sam_reader_test.cpp index 72b17a280..1eb8b1f63 100644 --- a/test/indexed_sam_reader_test.cpp +++ b/test/indexed_sam_reader_test.cpp @@ -1,6 +1,8 @@ +#include + #include "indexed_sam_reader.h" +#include "test_utils.h" -#include using namespace std; using namespace gamgee; @@ -77,12 +79,18 @@ BOOST_AUTO_TEST_CASE( indexed_single_readers_empty ) } BOOST_AUTO_TEST_CASE( indexed_single_readers_move_constructor_and_assignment ) { + auto r0 = IndexedSingleSamReader{"testdata/test_simple.bam", vector{"."}}; + auto m1 = check_move_constructor(r0); + auto m2 = IndexedSingleSamReader{"testdata/test_simple.bam", vector{"."}}; + BOOST_CHECK_EQUAL((*(m1.begin())).alignment_start(), (*(m2.begin())).alignment_start()); +} + +BOOST_AUTO_TEST_CASE( indexed_single_readers_begin_always_restarts ) { auto reader1 = IndexedSingleSamReader{"testdata/test_simple.bam", vector{"."}}; auto it1 = reader1.begin(); - auto reader2 = std::move(reader1); // check move constructor - reader1 = IndexedSingleSamReader{"testdata/test_simple.bam", vector{"."}}; // check move assignment - auto it2 = reader2.begin(); - auto it3 = reader1.begin(); - BOOST_CHECK_EQUAL((*it1).alignment_start(), (*it2).alignment_start()); // unlike the SingleSamReader, these should be the same because they are pointing at the exact same restarted iterator - BOOST_CHECK_EQUAL((*it1).alignment_start(), (*it3).alignment_start()); // these should be the same! both pointing at the first record + ++it1; + auto it2 = reader1.begin(); + BOOST_CHECK_NE((*it1).alignment_start(), (*it2).alignment_start()); + ++it2; + BOOST_CHECK_EQUAL((*it1).alignment_start(), (*it2).alignment_start()); } diff --git a/test/interval_test.cpp b/test/interval_test.cpp index 19a54f3cc..1f013a77b 100644 --- a/test/interval_test.cpp +++ b/test/interval_test.cpp @@ -1,7 +1,8 @@ -#include "interval.h" - #include +#include "interval.h" +#include "test_utils.h" + #include #include #include @@ -119,3 +120,19 @@ BOOST_AUTO_TEST_CASE( interval_equality ) i.set_chr("TAST"); BOOST_CHECK(!(i == j)); } + +BOOST_AUTO_TEST_CASE( interval_copy_and_move_constructors ) { + auto i0 = Interval {"A", 1'000, 2'000}; + auto copies = check_copy_constructor(i0); + auto c2 = get<1>(copies); + BOOST_CHECK(i0 == get<0>(copies)); + BOOST_CHECK(i0 == c2); + BOOST_CHECK(i0 == get<2>(copies)); + c2.set_start(1'500); + BOOST_CHECK(i0 != c2); + BOOST_CHECK(c2 != get<0>(copies)); + BOOST_CHECK(c2 != get<1>(copies)); + BOOST_CHECK(c2 != get<2>(copies)); + auto m1 = check_move_constructor(get<0>(copies)); + BOOST_CHECK(i0 == m1); +} diff --git a/test/sam_header_test.cpp b/test/sam_header_test.cpp index d380d42ea..209f6a525 100644 --- a/test/sam_header_test.cpp +++ b/test/sam_header_test.cpp @@ -1,7 +1,8 @@ -#include "sam_reader.h" - #include +#include "sam_reader.h" +#include "test_utils.h" + using namespace std; using namespace gamgee; @@ -18,11 +19,8 @@ BOOST_AUTO_TEST_CASE( sam_header ) { /** @todo Need a way to modify the header in between these copies/moves to make sure these are working properly! */ BOOST_AUTO_TEST_CASE( sam_header_constructors ) { auto reader = SingleSamReader{"testdata/test_simple.bam"}; - auto header1 = reader.header(); - auto header2 = header1; // copy constructor - auto header3 = std::move(header1); // move constructor - header1 = header2; // copy assignment - const auto header4 = std::move(header1); // transfer header1's memory somewhere else so we can reuse it for move assignment - header1 = std::move(header3); // move assignment - header1 = header1; // self assignment + auto h0 = reader.header(); + auto copies = check_copy_constructor(h0); + auto moves = check_copy_constructor(h0); + // need builder to be able to modify the header and check. At least this test will blow up if something is not functional. } diff --git a/test/sam_test.cpp b/test/sam_test.cpp index 2a71dd98c..279ab1434 100644 --- a/test/sam_test.cpp +++ b/test/sam_test.cpp @@ -4,6 +4,9 @@ #include "sam_reader.h" #include "sam_builder.h" #include "missing.h" + +#include "test_utils.h" + #include using namespace std; @@ -177,25 +180,26 @@ BOOST_AUTO_TEST_CASE( sam_in_place_cigar_modification ) { BOOST_CHECK_EQUAL(read_cigar[0], Cigar::make_cigar_element(30, CigarOperator::I)); } -BOOST_AUTO_TEST_CASE( sam_cigar_copy_and_move_constructors ) { - auto read = *(SingleSamReader{"testdata/test_simple.bam"}.begin()); - auto cigar = read.cigar(); - auto cigar_copy = cigar; - cigar_copy[0] = Cigar::make_cigar_element(3, CigarOperator::M); - BOOST_CHECK(cigar_copy != cigar); // check that modifying the copy doesn't affect the original - auto cigar_move = std::move(cigar); // move construct a new cigar - cigar_move[0] = Cigar::make_cigar_element(1, CigarOperator::D); - BOOST_CHECK(cigar_move != cigar_copy); // check that modifying the moved one doesn't affect the copy - cigar = cigar_copy; // check the copy assignment now that cigar has been moved to move_cigar - BOOST_CHECK(cigar == cigar_copy); // check that the cigar is now the same as the cigar_copy - BOOST_CHECK(cigar != cigar_move); // check that the cigar is not the same as the moved one - cigar[0] = Cigar::make_cigar_element(2, CigarOperator::N); - BOOST_CHECK(cigar != cigar_copy); // check that modifying the copied version doesn't affect the original - auto cigar_tmp = std::move(cigar); // take ownership of cigar's memory so we can play around with cigar again - cigar = std::move(cigar_move); // we should be back to the original again! - BOOST_CHECK(cigar == read.cigar()); - cigar = cigar; // check self assignment - BOOST_CHECK(cigar == read.cigar()); +BOOST_AUTO_TEST_CASE( sam_cigar_templated_copy_and_move_constructors ) { + auto it = SingleSamReader{"testdata/test_simple.bam"}.begin(); + const auto c0 = (*it).cigar(); + const auto copies = check_copy_constructor(c0); + auto c1 = get<0>(copies); + auto c2 = get<1>(copies); + auto c3 = get<2>(copies); + BOOST_CHECK(c0 == c1); + BOOST_CHECK(c0 == c2); + BOOST_CHECK(c0 == c3); + c1[0] = Cigar::make_cigar_element(30, CigarOperator::I); + BOOST_CHECK(c0 != c1); + auto m0 = (*it).cigar(); + auto m1 = check_move_constructor(m0); + auto m2 = (*it).cigar(); + BOOST_CHECK(m1 == m2); + m1[0] = Cigar::make_cigar_element(20, CigarOperator::I); + BOOST_CHECK(m1 == m2); // the underlying object is the same and it still exists + BOOST_CHECK(m0 == m1); // the underlying object is the same and it still exists (hasn't been destroyed, so they must still match) + BOOST_CHECK(m1 != c1); // check that modifying the moved doesn't affect the copied } BOOST_AUTO_TEST_CASE( invalid_cigar_access ) { @@ -217,25 +221,26 @@ BOOST_AUTO_TEST_CASE( comparing_different_cigars ) { BOOST_CHECK(read1.cigar() != read2.cigar()); } -BOOST_AUTO_TEST_CASE( sam_base_quals_copy_and_move_constructors ) { - auto read = *(SingleSamReader{"testdata/test_simple.bam"}.begin()); - auto bq = read.base_quals(); - auto bq_copy = bq; - bq_copy[0] = 99; - BOOST_CHECK(bq_copy != bq); // check that modifying the copy doesn't affect the original - auto bq_move = std::move(bq); // move construct a new bq - bq_move[0] = 90; - BOOST_CHECK(bq_move != bq_copy); // check that modifying the moved one doesn't affect the copy - bq = bq_copy; // check the copy assignment now that bq has been moved to move_bq - BOOST_CHECK(bq == bq_copy); // check that the bq is now the same as the bq_copy - BOOST_CHECK(bq != bq_move); // check that the bq is not the same as the moved one - bq[0] = 93; - BOOST_CHECK(bq != bq_copy); // check that modifying the copied version doesn't affect the original - auto bq_tmp = std::move(bq); // take ownership of bq's memory so we can play around with bq again - bq = std::move(bq_move); // we should be back to the original again! - BOOST_CHECK(bq == read.base_quals()); - bq = bq; // check self assignment - BOOST_CHECK(bq == read.base_quals()); +BOOST_AUTO_TEST_CASE( sam_base_quals_templated_copy_and_move_constructors ) { + auto it = SingleSamReader{"testdata/test_simple.bam"}.begin(); + auto c0 = (*it).base_quals(); + auto copies = check_copy_constructor(c0); + auto c1 = get<0>(copies); + auto c2 = get<1>(copies); + auto c3 = get<2>(copies); + BOOST_CHECK(c0 == c1); + BOOST_CHECK(c0 == c2); + BOOST_CHECK(c0 == c3); + c1[0] = 99; + BOOST_CHECK(c0 != c1); + auto m0 = (*it).base_quals(); + auto m1 = check_move_constructor(m0); + auto m2 = (*it).base_quals(); + BOOST_CHECK(m1 == m2); + m1[0] = 90; + BOOST_CHECK(m1 == m2); // the underlying object is the same and it still exists + BOOST_CHECK(m0 == m1); // the underlying object is the same and it still exists (hasn't been destroyed, so they must still match) + BOOST_CHECK(m1 != c2); // check that modifying the moved doesn't affect the copied } BOOST_AUTO_TEST_CASE( comparing_different_base_quals ) { @@ -247,25 +252,26 @@ BOOST_AUTO_TEST_CASE( comparing_different_base_quals ) { BOOST_CHECK(read1.base_quals() != read2.base_quals()); } -BOOST_AUTO_TEST_CASE( sam_read_bases_copy_and_move_constructors ) { - auto read = *(SingleSamReader{"testdata/test_simple.bam"}.begin()); - auto bases = read.bases(); - auto bases_copy = bases; - bases_copy.set_base(0, Base::C); - BOOST_CHECK(bases_copy != bases); // check that modifying the copy doesn't affect the original - auto bases_move = std::move(bases); // move construct a new bases - bases_move.set_base(0, Base::N); - BOOST_CHECK(bases_move != bases_copy); // check that modifying the moved one doesn't affect the copy - bases = bases_copy; // check the copy assignment now that bases has been moved to move_bases - BOOST_CHECK(bases == bases_copy); // check that the bases is now the same as the bases_copy - BOOST_CHECK(bases != bases_move); // check that the bases is not the same as the moved one - bases.set_base(0, Base::T); - BOOST_CHECK(bases != bases_copy); // check that modifying the copied version doesn't affect the original - auto bases_tmp = std::move(bases); // take ownership of bases's memory so we can play around with bases again - bases = std::move(bases_move); // we should be back to the original again! - BOOST_CHECK(bases == read.bases()); - bases = bases; // check self assignment - BOOST_CHECK(bases == read.bases()); +BOOST_AUTO_TEST_CASE( sam_read_bases_templated_copy_and_move_constructors ) { + auto it = SingleSamReader{"testdata/test_simple.bam"}.begin(); + auto c0 = (*it).bases(); + auto copies = check_copy_constructor(c0); + auto c1 = get<0>(copies); + auto c2 = get<1>(copies); + auto c3 = get<2>(copies); + BOOST_CHECK(c0 == c1); + BOOST_CHECK(c0 == c2); + BOOST_CHECK(c0 == c3); + c1.set_base(0, Base::C); + BOOST_CHECK(c0 != c1); + auto m0 = (*it).bases(); + auto m1 = check_move_constructor(m0); + auto m2 = (*it).bases(); + BOOST_CHECK(m1 == m2); + m1.set_base(0, Base::N); + BOOST_CHECK(m1 == m2); // the underlying object is the same and it still exists + BOOST_CHECK(m0 == m1); // the underlying object is the same and it still exists (hasn't been destroyed, so they must still match) + BOOST_CHECK(m1 != c2); // check that modifying the moved doesn't affect the copied } BOOST_AUTO_TEST_CASE( comparing_different_read_bases ) { @@ -361,19 +367,26 @@ BOOST_AUTO_TEST_CASE( sam_read_tags ) { BOOST_CHECK(missing(not_a_string_tag)); // this should yield "not a char" which is equal to a missing value } -BOOST_AUTO_TEST_CASE( sam_copy_constructor ) { - const auto read1 = *(SingleSamReader{"testdata/test_simple.bam"}.begin()); - auto read2 = read1; // copy read1 - read2.set_alignment_start(5000); - BOOST_CHECK(read1.alignment_start() != read2.alignment_start()); - read2 = read1; // copy assignment test - BOOST_CHECK_EQUAL(read1.alignment_start(), read2.alignment_start()); - read2.set_alignment_start(1); - read2 = read2; // check self assignment - BOOST_CHECK_EQUAL(read2.alignment_start(), 1); - auto read3 = read1; // check that variable length data field modifications don't affect the original record - read3.base_quals()[0] = 90; - BOOST_CHECK(read1.base_quals()[0] != read3.base_quals()[0]); +BOOST_AUTO_TEST_CASE( sam_templated_copy_and_move_constructors ) { + auto it = SingleSamReader{"testdata/test_simple.bam"}.begin(); + auto c0 = *it; + auto copies = check_copy_constructor(c0); + auto c1 = get<0>(copies); + auto c2 = get<1>(copies); + auto c3 = get<2>(copies); + BOOST_CHECK_EQUAL(c0.alignment_start(), c1.alignment_start()); + BOOST_CHECK_EQUAL(c0.alignment_start(), c2.alignment_start()); + BOOST_CHECK_EQUAL(c0.alignment_start(), c3.alignment_start()); + c1.set_alignment_start(1); + BOOST_CHECK_NE(c0.alignment_start(), c1.alignment_start()); + auto m0 = *it; + auto m1 = check_move_constructor(m0); + BOOST_CHECK(m0.empty()); + auto m2 = *it; + BOOST_CHECK_EQUAL(m1.alignment_start(), m2.alignment_start()); + m1.set_alignment_start(5000); + BOOST_CHECK_NE(m1.alignment_start(), m2.alignment_start()); // the underlying object is the same and it still exists + BOOST_CHECK_NE(m1.alignment_start(), c2.alignment_start()); // check that modifying the moved doesn't affect the copied } void check_read_alignment_starts_and_stops(const Sam& read, const uint32_t astart, const uint32_t astop, const uint32_t ustart, const uint32_t ustop) { diff --git a/test/test_utils.h b/test/test_utils.h new file mode 100644 index 000000000..ea7f0f042 --- /dev/null +++ b/test/test_utils.h @@ -0,0 +1,53 @@ +#ifndef gamgee_test_utils__guard +#define gamgee_test_utils__guard + +#include + +/** + * @brief test code for copy construction and copy assignment for any copy enabled object + * + * This tests copy construction, copy assignment and checks for self copy + * assignment. The starting object is copied to three different objects using + * all the above procedures. It returns a tuple with all three copied objects + * for you to verify that the copy occurred and that it didn't affect the + * original object. This is extremely useful when writing tests for a new class. + * + * @tparam T any class that is copy constructible and copy assignable + * @param original a simple object of class T to make the copies from + * @return a tuple with all three copied objects + */ +template +std::tuple check_copy_constructor (T& original) { + auto obj2 = original; // copy construction + auto obj3 = original; // copy construction + obj2 = obj2; // check self copy-assignment + obj3 = obj2; // copy assignment + return std::make_tuple(original, obj2, obj3); +} + + /** + * @brief test code for move construction and move assignment for any move enabled object + * + * This tests move construction, move assignment and checks for self move + * assignment. The starting object is moved through three different objects using + * all the above procedures. It returns the final moved to object + * for you to verify that the move occurred and that it still matches the + * original object. This is extremely useful when writing tests for a new class. + * + * @warning the original object passed in will be forcefully moved from, therefore in unusable state. + * + * @tparam T any class that is move constructible and move assignable + * @param original a simple object of class T to move from (it will be destroyed) + * @return the last moved to object + */ +template +T check_move_constructor (T& original) { + auto obj2 = std::move(original); // move construction + auto obj3 = std::move(obj2); // create a new object (we can't rely on default construction) + obj2 = std::move(obj3); // check move-assignment + return obj2; +} + + + +#endif diff --git a/test/variant_header_test.cpp b/test/variant_header_test.cpp index c6eea416b..df0d6335a 100644 --- a/test/variant_header_test.cpp +++ b/test/variant_header_test.cpp @@ -1,4 +1,5 @@ #include +#include "test_utils.h" #include "variant_header_builder.h" #include "missing.h" @@ -52,3 +53,17 @@ BOOST_AUTO_TEST_CASE( variant_header_builder_simple_building ) { BOOST_CHECK_EQUAL(vh.field_index("PASS"), 0); } +BOOST_AUTO_TEST_CASE( variant_header_move_and_copy_constructor ) { + auto builder = VariantHeaderBuilder{}; + builder.add_sample("S1"); + auto h0 = builder.build(); + auto copies = check_copy_constructor(h0); + auto c2 = get<2>(copies); + BOOST_CHECK_EQUAL_COLLECTIONS(h0.samples().begin(), h0.samples().end(), get<0>(copies).samples().begin(), get<0>(copies).samples().end()); + BOOST_CHECK_EQUAL_COLLECTIONS(h0.samples().begin(), h0.samples().end(), get<1>(copies).samples().begin(), get<1>(copies).samples().end()); + BOOST_CHECK_EQUAL_COLLECTIONS(h0.samples().begin(), h0.samples().end(), c2.samples().begin(), c2.samples().end()); + auto m1 = check_move_constructor(get<1>(copies)); + BOOST_CHECK_EQUAL_COLLECTIONS(h0.samples().begin(), h0.samples().end(), m1.samples().begin(), m1.samples().end()); + // can't modify a variant header... so this is it for the test. +} + diff --git a/test/variant_reader_test.cpp b/test/variant_reader_test.cpp index db30394fe..8117f7c4c 100644 --- a/test/variant_reader_test.cpp +++ b/test/variant_reader_test.cpp @@ -5,6 +5,7 @@ #include "indexed_variant_reader.h" #include "indexed_variant_iterator.h" #include "missing.h" +#include "test_utils.h" #include @@ -478,31 +479,6 @@ BOOST_AUTO_TEST_CASE( single_variant_reader_vector_too_large ) BOOST_CHECK_THROW((SingleVariantReader{vector{"testdata/test_variants.vcf", "testdata/test_variants.vcf"}}), std::runtime_error); } -BOOST_AUTO_TEST_CASE( single_variant_reader_move_test ) { - auto reader1 = SingleVariantReader{"testdata/test_variants.vcf"}; - - // move construct - auto reader2 = std::move(reader1); - - // move assign - auto reader3 = SingleVariantReader{"testdata/test_variants_missing_data.vcf"}; // different file - reader3 = std::move(reader2); - - auto truth_index = 0u; - for (const auto& record : reader3) { - check_variant_basic_api(record, truth_index); - check_quals_api(record, truth_index); - check_alt_api(record, truth_index); - check_filters_api(record, truth_index); - check_genotype_quals_api(record,truth_index); - check_phred_likelihoods_api(record, truth_index); - check_individual_field_api(record, truth_index); - check_shared_field_api(record, truth_index); - check_genotype_api(record, truth_index); - ++truth_index; - } -} - BOOST_AUTO_TEST_CASE( variant_iterator_move_test ) { auto reader = SingleVariantReader{"testdata/test_variants.vcf"}; auto iter1 = reader.begin(); @@ -808,3 +784,10 @@ BOOST_AUTO_TEST_CASE( indexed_variant_iterator_move_test ) { BOOST_CHECK_EQUAL(rec1.alignment_start(), rec3.alignment_start()); } } + +BOOST_AUTO_TEST_CASE( variant_reader_move_constructor ) { + auto r0 = SingleVariantReader{"testdata/test_variants.bcf"}; + auto r1 = SingleVariantReader{"testdata/test_variants.bcf"}; + auto m1 = check_move_constructor(r1); + BOOST_CHECK_EQUAL(r0.begin().operator*().alignment_start(), m1.begin().operator*().alignment_start()); +}