// ****************************************************************************
//
//          Aevol - An in silico experimental evolution platform
//
// ****************************************************************************
//
// Copyright: See the AUTHORS file provided with the package or <www.aevol.fr>
// Web: http://www.aevol.fr/
// E-mail: See <http://www.aevol.fr/contact/>
// Original Authors : Guillaume Beslon, Carole Knibbe, David Parsons
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
//*****************************************************************************

#include <inttypes.h>
#include <cstring>

#include <list>
#include <vector>
#include <memory>

#include <gtest/gtest.h>

#include "DnaFactory.h"
#include "ExpSetup.h"
#include "Individual.h"
#include "macros.h"
#include "MutationParams.h"
#include "Strand.h"

using namespace aevol;

//############################################################################
//                                                                           #
//                         Class EukTest_mutations                           #
//                                                                           #
//############################################################################
class EukTest_mutations : public testing::Test {
 protected:
  virtual void SetUp(void);
  virtual void TearDown(void);

  std::unique_ptr<Individual> indiv1;
  std::unique_ptr<Individual> indiv2;
  std::unique_ptr<Individual> indiv1A;
  std::unique_ptr<Individual> indiv2A;
  std::unique_ptr<Individual> indiv1B;
  std::unique_ptr<Individual> indiv2B;
  std::unique_ptr<Individual> indiv1C;
  std::unique_ptr<Individual> indiv2C;
  std::unique_ptr<Individual> indiv1D;
  std::unique_ptr<Individual> indiv2D;
  std::unique_ptr<Individual> indiv1E;
  std::unique_ptr<Individual> indiv2E;
};

// ===========================================================================
//                                 Public Methods
// ===========================================================================
void EukTest_mutations::SetUp(void) {
  // Build ad-hoc genomes
  // (and reverse to test the same things on the lagging strand.):
  //
  // indiv1: (prom + AS + AG + term)
  // indiv2: (term + AS + lag_AG + AS + lag_prom)
  // Test on each : - inversion of full sequence
  //                - inversion of AS+AG+AS
  //                - duplication of prom-1 toward the other end of genome
  //                - duplication of full prom before self
  //                - duplication of full prom toward the other end of genome
  //
  // AS = Arbitrary Sequence
  // AG = Arbitrary Gene
  // Do not modify the sequences !

  // Define a few arbitrary sequences
  std::array<std::string, 5> as = {"0011", "11101", "110011", "11000", "000101"};

  const char* SHINE_DAL_SEQ     = "011011";
  const char* SHINE_DAL_SEQ_LAG = "001001";
  // Define an arbitrary gene
  std::string gene = std::string(SHINE_DAL_SEQ) + "0011000100110110010001";

  std::string lag_gene = "0111011001001101110011" + std::string(SHINE_DAL_SEQ_LAG);

  // Define an arbitrary terminator
  std::string term = "01000001101";

  // Define a few arbitrary promoters
  std::array<std::string, 2> prom = {
      "0101010001110110010110",  // dist from consensus: 2 => basal level: 0.6
      "0101011001110010010010"   // dist from consensus: 1 => basal level: 0.8
  };

  std::array<std::string, 2> lag_prom = {
      "1001011001000111010101",  // dist from consensus: 2 => basal level: 0.6
      "1011011011000110010101"   // dist from consensus: 1 => basal level: 0.8
  };

  const uint32_t seed = 347982374;
  std::shared_ptr<JumpingMT> prng = std::make_shared<JumpingMT>(seed);

  // Build REF indiv1
  // Construct a genome with these arbitrary sequences
  auto genome = prom[0] + as[2] + gene + as[2] + term ;

  indiv1 = Individual::make_from_sequences(genome, genome);

  // Do transcription and translation
  indiv1->locate_promoters();
  indiv1->prom_compute_RNA();
  indiv1->start_protein();
  indiv1->compute_protein();
  indiv1->translate_protein(1.0);

  //build REF indiv2
  genome = term + as[2] + lag_gene + as[4] + lag_prom[1];

  indiv2 = Individual::make_from_sequences(genome, genome);

  // Do transcription and translation
  indiv2->locate_promoters();
  indiv2->prom_compute_RNA();
  indiv2->start_protein();
  indiv2->compute_protein();
  indiv2->translate_protein(1.0);

  // TEST INVERSION (full sequence)
  indiv1A = Individual::make_clone(*indiv1);
  indiv1A->mutable_dna(Chrsm::A).do_inversion(0, indiv1A->dna(Chrsm::A).length());
  indiv1A->mutable_dna(Chrsm::B).do_inversion(0, indiv1A->dna(Chrsm::B).length());
  indiv1A->prom_compute_RNA();
  indiv1A->start_protein();
  indiv1A->compute_protein();
  indiv1A->translate_protein(1.0);

  indiv2A = Individual::make_clone(*indiv2);
  indiv2A->mutable_dna(Chrsm::A).do_inversion(0, indiv2A->dna(Chrsm::A).length());
  indiv2A->mutable_dna(Chrsm::B).do_inversion(0, indiv2A->dna(Chrsm::B).length());
  indiv2A->prom_compute_RNA();
  indiv2A->start_protein();
  indiv2A->compute_protein();
  indiv2A->translate_protein(1.0);

  // TEST INVERSION 2 (only AS+AG+AS )
  indiv1B = Individual::make_clone(*indiv1);
  // 22 prom size and 11 term size
  indiv1B->mutable_dna(Chrsm::A).do_inversion(22, indiv1B->dna(Chrsm::A).length() - 11);
  indiv1B->mutable_dna(Chrsm::B).do_inversion(22, indiv1B->dna(Chrsm::B).length() - 11);
  indiv1B->prom_compute_RNA();
  indiv1B->start_protein();
  indiv1B->compute_protein();
  indiv1B->translate_protein(1.0);

  indiv2B = Individual::make_clone(*indiv2);
  indiv2B->mutable_dna(Chrsm::A).do_inversion(11, indiv2B->dna(Chrsm::A).length() - 22);
  indiv2B->mutable_dna(Chrsm::B).do_inversion(11, indiv2B->dna(Chrsm::B).length() - 22);
  indiv2B->prom_compute_RNA();
  indiv2B->start_protein();
  indiv2B->compute_protein();
  indiv2B->translate_protein(1.0);

  // TEST Duplication 1 (part of promoter)
  indiv1C = Individual::make_clone(*indiv1);
  // 22 prom size and 11 term size
  indiv1C->mutable_dna(Chrsm::A).do_duplication(0, 21, indiv1C->dna(Chrsm::A).length());
  indiv1C->mutable_dna(Chrsm::B).do_duplication(0, 21, indiv1C->dna(Chrsm::B).length());
  indiv1C->prom_compute_RNA();
  indiv1C->start_protein();
  indiv1C->compute_protein();
  indiv1C->translate_protein(1.0);

  indiv2C = Individual::make_clone(*indiv2);
  indiv2C->mutable_dna(Chrsm::A).do_duplication(
      indiv2C->dna(Chrsm::A).length() - 21, indiv2C->dna(Chrsm::A).length(), 0);
  indiv2C->mutable_dna(Chrsm::B).do_duplication(
      indiv2C->dna(Chrsm::B).length() - 21, indiv2C->dna(Chrsm::B).length(), 0);
  indiv2C->prom_compute_RNA();
  indiv2C->start_protein();
  indiv2C->compute_protein();
  indiv2C->translate_protein(1.0);

  // TEST Duplication 2 (full promoter)
  indiv1D = Individual::make_clone(*indiv1);
  // 22 prom size and 11 term size
  indiv1D->mutable_dna(Chrsm::A).do_duplication(0, 22, indiv1D->dna(Chrsm::A).length());
  indiv1D->mutable_dna(Chrsm::B).do_duplication(0, 22, indiv1D->dna(Chrsm::B).length());
  indiv1D->prom_compute_RNA();
  indiv1D->start_protein();
  indiv1D->compute_protein();
  indiv1D->translate_protein(1.0);

  indiv2D = Individual::make_clone(*indiv2);
  indiv2D->mutable_dna(Chrsm::A).do_duplication(
      indiv2D->dna(Chrsm::A).length() - 22, indiv2D->dna(Chrsm::A).length(), 0);
  indiv2D->mutable_dna(Chrsm::B).do_duplication(
      indiv2D->dna(Chrsm::B).length() - 22, indiv2D->dna(Chrsm::B).length(), 0);
  indiv2D->prom_compute_RNA();
  indiv2D->start_protein();
  indiv2D->compute_protein();
  indiv2D->translate_protein(1.0);

  // TEST Duplication 2 (full promoter, doubling same prot)
  indiv1E = Individual::make_clone(*indiv1);
  // 22 prom size and 11 term size
  indiv1E->mutable_dna(Chrsm::A).do_duplication(0, 22, 0);
  indiv1E->mutable_dna(Chrsm::B).do_duplication(0, 22, 0);
  indiv1E->prom_compute_RNA();
  indiv1E->start_protein();
  indiv1E->compute_protein();
  indiv1E->translate_protein(1.0);

  indiv2E = Individual::make_clone(*indiv2);
  indiv2E->mutable_dna(Chrsm::A).do_duplication(
      indiv2E->dna(Chrsm::A).length() - 22, indiv2E->dna(Chrsm::A).length(), indiv2E->dna(Chrsm::A).length());
  indiv2E->mutable_dna(Chrsm::B).do_duplication(
      indiv2E->dna(Chrsm::B).length() - 22, indiv2E->dna(Chrsm::B).length(), indiv2E->dna(Chrsm::B).length());
  indiv2E->prom_compute_RNA();
  indiv2E->start_protein();
  indiv2E->compute_protein();
  indiv2E->translate_protein(1.0);
}

void EukTest_mutations::TearDown() {
}

// For each version of each individual constructed with a different
// fuzzy set implementation, we check that all values are correct.
// We don't need to change the fuzzy set implementation in the
// experimental setup again because it's only used at transcription and
// translation time.

TEST_F(EukTest_mutations, TestIndiv1) {
  // Check that we have the right number of promoters, terminators etc
  // and at the right positions
  // "right" means those values we have computed by hand
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(73, indiv1->dna(chrsm).length());

    // Check RNA list
    auto rna_list = indiv1->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LEADING, rna.strand_);
    EXPECT_EQ(0, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.6, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv1->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LEADING, prot->strand());
    EXPECT_EQ(41, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.6, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv2) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(73, indiv2->dna(chrsm).length());

    // Check RNA list
    auto rna_list = indiv2->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LAGGING, rna.strand_);
    EXPECT_EQ(72, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.8, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv2->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LAGGING, prot->strand());
    EXPECT_EQ(31, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.8, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv1A) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(73, indiv1A->dna(chrsm).length());

    // Check RNA list
    auto rna_list = indiv1A->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LAGGING, rna.strand_);
    EXPECT_EQ(72, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.6, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv1A->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LAGGING, prot->strand());
    EXPECT_EQ(31, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.6, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv2A) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(73, indiv2A->dna(chrsm).length());

    // Check RNA list
    auto rna_list = indiv2A->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LEADING, rna.strand_);
    EXPECT_EQ(0, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.8, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv2A->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LEADING, prot->strand());
    EXPECT_EQ(41, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.8, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv1B) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(73, indiv1B->dna(chrsm).length());

    // Check RNA list
    auto rna_list = indiv1B->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LEADING, rna.strand_);
    EXPECT_EQ(0, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.6, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv1B->proteins(chrsm);
    EXPECT_EQ(0, prot_list.size());
  }
}

TEST_F(EukTest_mutations, TestIndiv2B) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(73, indiv2B->dna(chrsm).length());

    // Check RNA list
    auto rna_list = indiv2B->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LAGGING, rna.strand_);
    EXPECT_EQ(72, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.8, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv2B->proteins(chrsm);
    EXPECT_EQ(0, prot_list.size());
  }
}

TEST_F(EukTest_mutations, TestIndiv1C) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(94, indiv1C->dna(chrsm).length());

    // Check Prom list
    EXPECT_EQ(1, indiv1C->annotated_chromosome(chrsm).promoters().promoter_count());

    // Check RNA list
    auto rna_list = indiv1C->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LEADING, rna.strand_);
    EXPECT_EQ(0, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.6, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv1C->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LEADING, prot->strand());
    EXPECT_EQ(41, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.6, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv2C) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(94, indiv2C->dna(chrsm).length());

    // Check Prom list
    EXPECT_EQ(1, indiv2C->annotated_chromosome(chrsm).promoters().promoter_count());

    // Check RNA list
    auto rna_list = indiv2C->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LAGGING, rna.strand_);
    EXPECT_EQ(93, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.8, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv2C->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LAGGING, prot->strand());
    EXPECT_EQ(52, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.8, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv1D) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(95, indiv1D->dna(chrsm).length());

    // Check Prom list
    EXPECT_EQ(2, indiv1D->annotated_chromosome(chrsm).promoters().promoter_count());
    EXPECT_EQ(0, indiv1D->annotated_chromosome(chrsm).promoters().at(0)->pos());
    EXPECT_EQ(73, indiv1D->annotated_chromosome(chrsm).promoters().at(1)->pos());

    // Check RNA list
    auto rna_list = indiv1D->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LEADING, rna.strand_);
    EXPECT_EQ(0, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.6, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv1D->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LEADING, prot->strand());
    EXPECT_EQ(41, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.6, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv2D) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(95, indiv2D->dna(chrsm).length());

    // Check Prom list
    EXPECT_EQ(2, indiv2D->annotated_chromosome(chrsm).promoters().promoter_count());
    EXPECT_EQ(94, indiv2D->annotated_chromosome(chrsm).promoters().at(0)->pos());
    EXPECT_EQ(21, indiv2D->annotated_chromosome(chrsm).promoters().at(1)->pos());

    // Check RNA list
    auto rna_list = indiv2D->rnas(chrsm);
    EXPECT_EQ(1, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *rna_it;
    EXPECT_EQ(Strand::LAGGING, rna.strand_);
    EXPECT_EQ(94, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.8, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv2D->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LAGGING, prot->strand());
    EXPECT_EQ(53, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.8, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
  }
}

TEST_F(EukTest_mutations, TestIndiv1E) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(95, indiv1E->dna(chrsm).length());

    // Check Prom list
    EXPECT_EQ(3, indiv1E->annotated_chromosome(chrsm).promoters().promoter_count());
    // We created a lagging one unintentionally
    EXPECT_EQ(0, indiv1E->annotated_chromosome(chrsm).promoters().at(0)->pos());
    EXPECT_EQ(22, indiv1E->annotated_chromosome(chrsm).promoters().at(1)->pos());

    // Check RNA list
    auto rna_list = indiv1E->rnas(chrsm);
    EXPECT_EQ(2, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *(++rna_it);
    EXPECT_EQ(Strand::LEADING, rna.strand_);
    EXPECT_EQ(22, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.6, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv1E->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LEADING, prot->strand());
    EXPECT_EQ(63, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.6, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
    //2nd Rna stopped before prot (term in Prom)
  }
}

TEST_F(EukTest_mutations, TestIndiv2E) {
  for (auto chrsm: {Chrsm::A, Chrsm::B}) {
    // Check genome size
    EXPECT_EQ(95, indiv2E->dna(chrsm).length());

    // Check Prom list
    EXPECT_EQ(2, indiv2E->annotated_chromosome(chrsm).promoters().promoter_count());
    EXPECT_EQ(94, indiv2E->annotated_chromosome(chrsm).promoters().at(0)->pos());
    EXPECT_EQ(72, indiv2E->annotated_chromosome(chrsm).promoters().at(1)->pos());

    // Check RNA list
    auto rna_list = indiv2E->rnas(chrsm);
    EXPECT_EQ(2, rna_list.size());

    auto rna_it     = rna_list.begin();
    const auto& rna = *(++rna_it);
    EXPECT_EQ(Strand::LAGGING, rna.strand_);
    EXPECT_EQ(72, rna.prom->pos());
    EXPECT_FLOAT_EQ(0.8, rna.e);
    EXPECT_EQ(51, rna.length());

    // Check protein list
    auto& prot_list = indiv2E->proteins(chrsm);
    EXPECT_EQ(1, prot_list.size());

    auto prot_it     = prot_list.begin();
    const auto* prot = *prot_it;
    EXPECT_EQ(Strand::LAGGING, prot->strand());
    EXPECT_EQ(31, prot->position_first_aa());
    EXPECT_EQ(4, prot->size());
    EXPECT_FLOAT_EQ(0.8, prot->e());
    EXPECT_EQ(false, prot->is_duplicate());
    EXPECT_EQ(1, prot->rna_list().size());
    //2nd Rna stopped before prot (term in Prom)
  }
}

// ===========================================================================
//                                Protected Methods
// ===========================================================================

// ===========================================================================
//                              Non inline accessors
// ===========================================================================
