// Author: David Alexander

#include <gtest/gtest.h>
#include <boost/assign.hpp>
#include <string>
#include <vector>

#include <ConsensusCore/Quiver/MultiReadMutationScorer.hpp>
#include <ConsensusCore/Quiver/QuiverConfig.hpp>
#include <ConsensusCore/Quiver/ReadScorer.hpp>
#include <ConsensusCore/Quiver/SimpleRecursor.hpp>
#include <ConsensusCore/Quiver/SseRecursor.hpp>
#include <ConsensusCore/Sequence.hpp>

#include "ParameterSettings.hpp"

using namespace ConsensusCore;  // NOLINT
using namespace boost::assign;  // NOLINT

//
// Convenience routines for testing
//
Read AnonymousRead(std::string seq)
{
    return Read(QvSequenceFeatures(seq), "anonymous", "unknown");
}

MappedRead AnonymousMappedRead(std::string seq, StrandEnum strand, int tStart, int tEnd)
{
    return MappedRead(AnonymousRead(seq), strand, tStart, tEnd);
}

//
// Tests for supporting code: QuiverConfigTable, OrientedMutation,
// ReadScoresMutation
//

TEST(QuiverConfigTableTests, IllegalChemistry)
{
    QuiverConfig qc = TestingConfig("*");
    QuiverConfigTable qt;

    EXPECT_THROW(qt.Insert(qc), InvalidInputError);
}

TEST(MutationOrientationTests, ReadScoresMutation1)
{
    //  012345678901
    //    >>>>>>>>    mr
    MappedRead mr(AnonymousRead("G"), FORWARD_STRAND, 2, 10);

    for (int p = 0; p <= 11; p++) {
        Mutation mSubs(SUBSTITUTION, p, 'G');
        Mutation mDel(DELETION, p, '-');
        Mutation mIns(INSERTION, p, 'G');

        if (p < mr.TemplateStart) {
            EXPECT_TRUE(!ReadScoresMutation(mr, mSubs) && !ReadScoresMutation(mr, mDel) &&
                        !ReadScoresMutation(mr, mIns));
        } else if (p == mr.TemplateStart) {
            EXPECT_TRUE(ReadScoresMutation(mr, mSubs) && ReadScoresMutation(mr, mDel) &&
                        !ReadScoresMutation(mr, mIns));
        } else if (p < mr.TemplateEnd) {
            EXPECT_TRUE(ReadScoresMutation(mr, mSubs) && ReadScoresMutation(mr, mDel) &&
                        ReadScoresMutation(mr, mIns));
        } else if (p == mr.TemplateEnd) {
            EXPECT_TRUE(!ReadScoresMutation(mr, mSubs) && !ReadScoresMutation(mr, mDel) &&
                        ReadScoresMutation(mr, mIns));
        } else if (p > mr.TemplateEnd) {
            EXPECT_TRUE(!ReadScoresMutation(mr, mSubs) && !ReadScoresMutation(mr, mDel) &&
                        !ReadScoresMutation(mr, mIns));
        }
    }
}

TEST(MutationOrientationTests, ReadScoresMutation2)
{
    //  012345678901
    //    >>>>>>>>    mr
    MappedRead mr(AnonymousRead("G"), FORWARD_STRAND, 2, 10);

    for (int p = 0; p <= 11; p++) {
        Mutation mSubs2(SUBSTITUTION, p, p + 2, "GG");
        Mutation mDel2(DELETION, p, p + 2, "");
        if (p >= 1 && p <= 9) {
            EXPECT_TRUE(ReadScoresMutation(mr, mSubs2) && ReadScoresMutation(mr, mDel2));
        } else {
            EXPECT_TRUE(!ReadScoresMutation(mr, mSubs2) && !ReadScoresMutation(mr, mDel2));
        }
    }
}

TEST(MutationOrientationTests, OrientedMutation)
{
    //  012345678901
    //    >>>>>>>>    mr1
    //    <<<<<<<<    mr2
    MappedRead mr1(AnonymousRead("G"), FORWARD_STRAND, 2, 10);
    MappedRead mr2(AnonymousRead("G"), REVERSE_STRAND, 2, 10);

    for (int p = 2; p <= 9; p++) {
        Mutation mSubs(SUBSTITUTION, p, 'G');
        Mutation mDel(DELETION, p, '-');

        EXPECT_EQ(Mutation(SUBSTITUTION, p - mr1.TemplateStart, 'G'), OrientedMutation(mr1, mSubs));
        EXPECT_EQ(Mutation(DELETION, p - mr1.TemplateStart, '-'), OrientedMutation(mr1, mDel));
        EXPECT_EQ(Mutation(SUBSTITUTION, mr2.TemplateEnd - 1 - p, 'C'),
                  OrientedMutation(mr2, mSubs));
        EXPECT_EQ(Mutation(DELETION, mr2.TemplateEnd - 1 - p, '-'), OrientedMutation(mr2, mDel));
    }

    for (int p = 3; p <= 10; p++) {
        Mutation mIns(INSERTION, p, 'G');
        Mutation mIns2(INSERTION, p, p, "GT");

        EXPECT_EQ(Mutation(INSERTION, p - mr1.TemplateStart, 'G'), OrientedMutation(mr1, mIns));
        EXPECT_EQ(Mutation(INSERTION, p - mr1.TemplateStart, p - mr1.TemplateStart, "GT"),
                  OrientedMutation(mr1, mIns2));
        EXPECT_EQ(Mutation(INSERTION, mr2.TemplateEnd - p, 'C'), OrientedMutation(mr2, mIns));
        EXPECT_EQ(Mutation(INSERTION, mr2.TemplateEnd - p, mr2.TemplateEnd - p, "AC"),
                  OrientedMutation(mr2, mIns2));
    }

    for (int p = 1; p <= 9; p++) {
        Mutation mSubs2(SUBSTITUTION, p, p + 2, "GG");
        Mutation mDel2(DELETION, p, p + 2, "");

        if (p == 1) {
            EXPECT_EQ(Mutation(SUBSTITUTION, 0, 1, "G"), OrientedMutation(mr1, mSubs2));
            EXPECT_EQ(Mutation(DELETION, 0, 1, ""), OrientedMutation(mr1, mDel2));
            EXPECT_EQ(Mutation(SUBSTITUTION, 7, 8, "C"), OrientedMutation(mr2, mSubs2));
            EXPECT_EQ(Mutation(DELETION, 7, 8, ""), OrientedMutation(mr2, mDel2));
        } else if (p == 9) {
            EXPECT_EQ(Mutation(SUBSTITUTION, 7, 8, "G"), OrientedMutation(mr1, mSubs2));
            EXPECT_EQ(Mutation(DELETION, 7, 8, ""), OrientedMutation(mr1, mDel2));
            EXPECT_EQ(Mutation(SUBSTITUTION, 0, 1, "C"), OrientedMutation(mr2, mSubs2));
            EXPECT_EQ(Mutation(DELETION, 0, 1, ""), OrientedMutation(mr2, mDel2));
        } else {
            EXPECT_EQ(Mutation(SUBSTITUTION, p - 2, p, "GG"), OrientedMutation(mr1, mSubs2));
            EXPECT_EQ(Mutation(DELETION, p - 2, p, ""), OrientedMutation(mr1, mDel2));
            EXPECT_EQ(Mutation(SUBSTITUTION, mr2.TemplateEnd - p - 2, mr2.TemplateEnd - p, "CC"),
                      OrientedMutation(mr2, mSubs2));
            EXPECT_EQ(Mutation(DELETION, mr2.TemplateEnd - p - 2, mr2.TemplateEnd - p, ""),
                      OrientedMutation(mr2, mDel2));
        }
    }
}

//
//  Tests for the multi read mutation scorer itself
//

TYPED_TEST_CASE(MultiReadMutationScorerTest, testing::Types<SparseSseQvRecursor>);

template <typename R>
class MultiReadMutationScorerTest : public testing::Test
{
public:
    typedef MultiReadMutationScorer<R> MMS;

protected:
    MultiReadMutationScorerTest()
        : testingConfig_(TestingParams(), ALL_MOVES, BandingOptions(4, 200), -500)
    {
        testingConfigs_.InsertDefault(testingConfig_);
    }

    virtual ~MultiReadMutationScorerTest() {}

protected:
    QuiverConfig testingConfig_;
    QuiverConfigTable testingConfigs_;
};

#define MMS MultiReadMutationScorer<TypeParam>
#define MS MutationScorer<TypeParam>
#define E typename TypeParam::EvaluatorType

#define config (this->testingConfig_)
#define params (this->testingConfig_.QvParams)

TYPED_TEST(MultiReadMutationScorerTest, Template)
{
    //                 0123456789
    std::string fwd = "AAAATTTTGG";
    std::string rev = ReverseComplement(fwd);

    // Make sure the Template function works right
    MMS mScorer(this->testingConfigs_, fwd);
    ASSERT_EQ(fwd, mScorer.Template());
    ASSERT_EQ(fwd, mScorer.Template(FORWARD_STRAND));
    ASSERT_EQ(rev, mScorer.Template(REVERSE_STRAND));
    ASSERT_EQ(fwd, mScorer.Template(FORWARD_STRAND, 0, 10));
    ASSERT_EQ(rev, mScorer.Template(REVERSE_STRAND, 0, 10));
    ASSERT_EQ("AT", mScorer.Template(FORWARD_STRAND, 3, 5));
    ASSERT_EQ("AT", mScorer.Template(REVERSE_STRAND, 3, 5));
    ASSERT_EQ("TTTT", mScorer.Template(FORWARD_STRAND, 4, 8));
    ASSERT_EQ("AAAA", mScorer.Template(REVERSE_STRAND, 4, 8));
}

TYPED_TEST(MultiReadMutationScorerTest, BasicTest)
{
    std::string tpl = "TTGATTACATT";
    std::string revTpl = ReverseComplement(tpl);
    int tStart = 0;
    int tEnd = tpl.length();

    MMS mScorer(this->testingConfigs_, tpl);
    MappedRead mr(AnonymousRead("TTGATTACATT"), FORWARD_STRAND, tStart, tEnd);
    mScorer.AddRead(mr);

    Mutation noOpMutation(SUBSTITUTION, 6, 'A');
    Mutation insertMutation(INSERTION, 6, 'A');
    Mutation substitutionMutation(SUBSTITUTION, 6, 'T');
    Mutation deletionMutation(DELETION, 6, '-');

    EXPECT_EQ(0, mScorer.Score(noOpMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Merge[0], mScorer.Score(insertMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Mismatch, mScorer.Score(substitutionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Nce, mScorer.Score(deletionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());

    MappedRead mr2(AnonymousRead("TTGATTACATT"), FORWARD_STRAND, tStart, tEnd);
    mScorer.AddRead(mr2);

    EXPECT_EQ(0, mScorer.Score(noOpMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(-4, mScorer.Score(insertMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(-20, mScorer.Score(substitutionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(-16, mScorer.Score(deletionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());

    std::vector<Mutation> muts;
    muts += insertMutation;
    mScorer.ApplyMutations(muts);
    EXPECT_EQ("TTGATTAACATT", mScorer.Template());

    Mutation newNoOpMutation(SUBSTITUTION, 6, 'A');
    EXPECT_EQ(0, mScorer.Score(newNoOpMutation));
}

TYPED_TEST(MultiReadMutationScorerTest, ManyMutationTest)
{
    std::string tpl = "TTGACGTACGTGTGACACAGTACAGATTACAAACCGGTAGACATTACATT";
    std::string revTpl = ReverseComplement(tpl);

    MMS mScorer(this->testingConfigs_, tpl);
    MappedRead mr(AnonymousRead("TTGATTACATT"), FORWARD_STRAND, 0, tpl.length());
    mScorer.AddRead(mr);

    std::vector<Mutation> muts;
    const int tplLen = tpl.length();
    for (int i = 0; i < tplLen; i += 2) {
        Mutation mutation(SUBSTITUTION, i, 'A');
        muts += mutation;
    }

    mScorer.ApplyMutations(muts);
    EXPECT_EQ(tpl.length(), mScorer.Template().length());
}

TYPED_TEST(MultiReadMutationScorerTest, CopyConstructorTest)
{
    std::string tpl = "TTGATTACATT";
    std::string revTpl = ReverseComplement(tpl);

    MMS mScorer(this->testingConfigs_, tpl);
    MappedRead mr(AnonymousRead("TTGATTACATT"), FORWARD_STRAND, 0, tpl.length());
    mScorer.AddRead(mr);

    // Run the copy constructor of MultiReadMutationScorer
    MMS mCopy(mScorer);

    Mutation noOpMutation(SUBSTITUTION, 6, 'A');
    Mutation insertMutation(INSERTION, 6, 'A');
    Mutation substitutionMutation(SUBSTITUTION, 6, 'T');
    Mutation deletionMutation(DELETION, 6, '-');

    EXPECT_EQ(0, mScorer.Score(noOpMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Merge[0], mScorer.Score(insertMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Mismatch, mScorer.Score(substitutionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Nce, mScorer.Score(deletionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());

    // Apply mutation to copy
    std::vector<Mutation> muts;
    muts += insertMutation;
    mCopy.ApplyMutations(muts);

    // copy template should change
    EXPECT_EQ("TTGATTAACATT", mCopy.Template());

    // original should be unchanged
    EXPECT_EQ("TTGATTACATT", mScorer.Template());

    // Score of original shouldn't change
    EXPECT_EQ(0, mScorer.Score(noOpMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Merge[0], mScorer.Score(insertMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Mismatch, mScorer.Score(substitutionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
    EXPECT_EQ(params.Nce, mScorer.Score(deletionMutation));
    EXPECT_EQ("TTGATTACATT", mScorer.Template());
}

TYPED_TEST(MultiReadMutationScorerTest, ReverseStrandTest)
{
    // Just make sure if we reverse complemented the universe,
    // everything would come out the same.
    std::string tpl = "AATGTAATCAA";
    MMS mScorer(this->testingConfigs_, tpl);
    MappedRead mr(AnonymousRead("TTGATTACATT"), REVERSE_STRAND, 0, tpl.length());
    mScorer.AddRead(mr);

    Mutation noOpMutation(SUBSTITUTION, 4, 'T');
    Mutation insertMutation(INSERTION, 5, 'T');
    Mutation substitutionMutation(SUBSTITUTION, 4, 'A');
    Mutation deletionMutation(DELETION, 4, '-');

    EXPECT_EQ(0, mScorer.Score(noOpMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());
    EXPECT_EQ(params.Merge[0], mScorer.Score(insertMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());
    EXPECT_EQ(params.Mismatch, mScorer.Score(substitutionMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());
    EXPECT_EQ(params.Nce, mScorer.Score(deletionMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());

    MappedRead mr2(AnonymousRead("TTGATTACATT"), REVERSE_STRAND, 0, tpl.length());
    mScorer.AddRead(mr2);

    EXPECT_EQ(0, mScorer.Score(noOpMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());
    EXPECT_EQ(2 * params.Merge[0], mScorer.Score(insertMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());
    EXPECT_EQ(2 * params.Mismatch, mScorer.Score(substitutionMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());
    EXPECT_EQ(2 * params.Nce, mScorer.Score(deletionMutation));
    EXPECT_EQ("AATGTAATCAA", mScorer.Template());

    std::vector<Mutation> muts;
    muts += insertMutation;
    mScorer.ApplyMutations(muts);
    EXPECT_EQ("AATGTTAATCAA", mScorer.Template());

    Mutation newNoOpMutation(SUBSTITUTION, 4, 'T');
    EXPECT_EQ(0, mScorer.Score(newNoOpMutation));
}

TYPED_TEST(MultiReadMutationScorerTest, TestMutationsAtBeginning)
{
    std::string tpl = "TTGATTACATT";

    MMS mScorer(this->testingConfigs_, tpl);
    MappedRead mr(AnonymousRead("TTGATTACATT"), FORWARD_STRAND, 0, tpl.length());
    mScorer.AddRead(mr);

    Mutation noOpMutation(SUBSTITUTION, 0, 'T');
    Mutation deletionMutation(DELETION, 0, '-');
    Mutation insertMutation(INSERTION, 0, 'A');
    Mutation insertMutation2(INSERTION, 1, 'A');

    EXPECT_EQ(0, mScorer.Score(noOpMutation));

    // Note that there is no actual way to test an insertion before
    // the first base ... the alignment just slides over.
    EXPECT_EQ(0, mScorer.Score(insertMutation));
    EXPECT_EQ(params.DeletionN, mScorer.Score(insertMutation2));
    EXPECT_EQ(params.Branch, mScorer.Score(deletionMutation));  // now there is a branch...
}

TYPED_TEST(MultiReadMutationScorerTest, TestMutationsAtEnd)
{
    //                 01234567890
    std::string tpl = "TTGATTACATT";

    MMS mScorer(this->testingConfigs_, tpl);
    MappedRead mr(AnonymousRead("TTGATTACATT"), FORWARD_STRAND, 0, tpl.length());
    mScorer.AddRead(mr);

    Mutation noOpMutation(SUBSTITUTION, 10, 'T');
    Mutation deletionMutation(DELETION, 10, '-');
    Mutation insertMutation(INSERTION, 11, 'A');
    Mutation insertMutation2(INSERTION, 12, 'A');

    EXPECT_EQ(0, mScorer.Score(noOpMutation));

    // Note that there is no actual way to test an insertion before
    // the first base ... the alignment just slides over.
    EXPECT_EQ(params.DeletionN, mScorer.Score(insertMutation));
    EXPECT_EQ(0, mScorer.Score(insertMutation2));
    EXPECT_EQ(params.Branch, mScorer.Score(deletionMutation));
}

TYPED_TEST(MultiReadMutationScorerTest, NonSpanningReadsTest1)
{
    // read1:                     >>>>>>>>>>>
    // read2:          <<<<<<<<<<<
    //                 0123456789012345678901
    std::string tpl = "AATGTAATCAATTGATTACATT";
    MMS mScorer(this->testingConfigs_, tpl);

    // mutations in the latter half
    Mutation noOpMutation1(SUBSTITUTION, 17, 'A');
    Mutation insertMutation1(INSERTION, 17, 'A');
    Mutation substitutionMutation1(SUBSTITUTION, 17, 'T');
    Mutation deletionMutation1(DELETION, 17, '-');

    // mutations in the first half
    Mutation noOpMutation2(SUBSTITUTION, 4, 'T');
    Mutation insertMutation2(INSERTION, 5, 'T');
    Mutation substitutionMutation2(SUBSTITUTION, 4, 'A');
    Mutation deletionMutation2(DELETION, 4, '-');

    mScorer.AddRead(AnonymousMappedRead("TTGATTACATT", FORWARD_STRAND, 11, 22));
    mScorer.AddRead(AnonymousMappedRead("TTGATTACATT", REVERSE_STRAND, 0, 11));

    EXPECT_EQ(0, mScorer.Score(noOpMutation1));
    EXPECT_EQ(params.Merge[0], mScorer.Score(insertMutation1));
    EXPECT_EQ(params.Mismatch, mScorer.Score(substitutionMutation1));
    EXPECT_EQ(params.Nce, mScorer.Score(deletionMutation1));

    EXPECT_EQ(0, mScorer.Score(noOpMutation2));
    EXPECT_EQ(params.Merge[0], mScorer.Score(insertMutation2));
    EXPECT_EQ(params.Mismatch, mScorer.Score(substitutionMutation2));
    EXPECT_EQ(params.Nce, mScorer.Score(deletionMutation2));

    EXPECT_EQ(tpl, mScorer.Template());

    std::vector<Mutation> muts;
    muts += insertMutation1, insertMutation2;
    mScorer.ApplyMutations(muts);
    EXPECT_EQ("AATGTTAATCAATTGATTAACATT", mScorer.Template());
}

TYPED_TEST(MultiReadMutationScorerTest, CopyTest)
{
    // read1:                     >>>>>>>>>>>
    // read2:          <<<<<<<<<<<
    //                 0123456789012345678901
    std::string tpl = "AATGTAATCAATTGATTACATT";
    MMS mScorer(this->testingConfigs_, tpl);
    mScorer.AddRead(AnonymousMappedRead("TTGATTACATT", FORWARD_STRAND, 11, 22));
    mScorer.AddRead(AnonymousMappedRead("TTGATTACATT", REVERSE_STRAND, 0, 11));
    MMS mScorerCopy(mScorer);

    ASSERT_EQ(mScorer.BaselineScore(), mScorerCopy.BaselineScore());
}

TYPED_TEST(MultiReadMutationScorerTest, MultiBaseSubstitutionsAtBounds)
{
    // read1:                     >>>>>>>>>
    // read2:            <<<<<<<<<
    //                 0123456789012345678901
    std::string tpl = "AATGTAATCAATTGATTACATT";
    MMS mScorer(this->testingConfigs_, tpl);
    mScorer.AddRead(AnonymousMappedRead("TTGATTACA", FORWARD_STRAND, 11, 20));
    mScorer.AddRead(AnonymousMappedRead("TTGATTACA", REVERSE_STRAND, 2, 11));

    EXPECT_EQ(0, mScorer.Score(Mutation(SUBSTITUTION, 0, 2, "MN")));
    EXPECT_EQ(params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 1, 3, "MN")));
    EXPECT_EQ(2 * params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 2, 4, "MN")));
    EXPECT_EQ(2 * params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 9, 11, "MN")));
    EXPECT_EQ(2 * params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 10, 12, "MN")));
    EXPECT_EQ(2 * params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 11, 13, "MN")));
    EXPECT_EQ(2 * params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 18, 20, "MN")));
    EXPECT_EQ(params.Mismatch, mScorer.Score(Mutation(SUBSTITUTION, 19, 21, "MN")));
    EXPECT_EQ(0, mScorer.Score(Mutation(SUBSTITUTION, 20, 22, "MN")));
}

TYPED_TEST(MultiReadMutationScorerTest, MultiBaseIndelsAtBounds)
{
    // read1:                     >>>>>>>>>
    // read2:            <<<<<<<<<
    //                 0123456789012345678901
    std::string tpl = "AATGTAATCAATTGATTACATT";
    MMS mScorer(this->testingConfigs_, tpl);
    mScorer.AddRead(AnonymousMappedRead("TTGATTACA", FORWARD_STRAND, 11, 20));
    mScorer.AddRead(AnonymousMappedRead("TTGATTACA", REVERSE_STRAND, 2, 11));

    // Insertions
    EXPECT_EQ(0, mScorer.Score(Mutation(INSERTION, 2, 2, "MN")));
    EXPECT_EQ(2 * params.DeletionN, mScorer.Score(Mutation(INSERTION, 3, 3, "MN")));
    EXPECT_EQ(2 * params.DeletionN, mScorer.Score(Mutation(INSERTION, 11, 11, "MN")));
    EXPECT_EQ(2 * params.DeletionN, mScorer.Score(Mutation(INSERTION, 12, 12, "MN")));
    EXPECT_EQ(2 * params.DeletionN, mScorer.Score(Mutation(INSERTION, 19, 19, "MN")));
    EXPECT_EQ(2 * params.DeletionN, mScorer.Score(Mutation(INSERTION, 20, 20, "MN")));
    EXPECT_EQ(0, mScorer.Score(Mutation(INSERTION, 21, 21, "MN")));

    // Deletions
    EXPECT_EQ(0, mScorer.Score(Mutation(DELETION, 0, 2, "")));
    EXPECT_EQ(params.Nce, mScorer.Score(Mutation(DELETION, 1, 3, "")));
    EXPECT_EQ(params.Nce + params.Branch, mScorer.Score(Mutation(DELETION, 2, 4, "")));
    EXPECT_EQ(2 * params.Nce, mScorer.Score(Mutation(DELETION, 9, 11, "")));
    EXPECT_EQ(2 * params.Branch, mScorer.Score(Mutation(DELETION, 10, 12, "")));
    EXPECT_EQ(2 * params.Nce, mScorer.Score(Mutation(DELETION, 11, 13, "")));
    EXPECT_EQ(params.Nce + params.Branch, mScorer.Score(Mutation(DELETION, 18, 20, "")));
    EXPECT_EQ(params.Nce, mScorer.Score(Mutation(DELETION, 19, 21, "")));
    EXPECT_EQ(0, mScorer.Score(Mutation(DELETION, 20, 22, "")));
}
