Program Listing for File Symbiont.test.cc

Return to documentation for file (source/test/default_mode_test/Symbiont.test.cc)

#include "../../default_mode/Host.h"
#include "../../default_mode/Symbiont.h"

TEST_CASE("Symbiont Constructor", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    double int_val = -2;
    REQUIRE_THROWS(new Symbiont(random, world, &config, int_val) );

    int_val = -1;
    Symbiont * s1 = new Symbiont(random, world, &config, int_val);
    CHECK(s1->GetIntVal() == int_val);
    CHECK(s1->GetAge() == 0);
    CHECK(s1->GetPoints() == 0);

    int_val = -1;
    double points = 10;
    Symbiont * s2 = new Symbiont(random, world, &config, int_val, points);
    CHECK(s2->GetIntVal() == int_val);
    CHECK(s2->GetAge() == 0);
    CHECK(s2->GetPoints() == points);

    int_val = 1;
    Symbiont * s3 = new Symbiont(random, world, &config, int_val);
    CHECK(s3->GetIntVal() == int_val);
    CHECK(s3->GetAge() == 0);
    CHECK(s3->GetPoints() == 0);

    int_val = 2;
    REQUIRE_THROWS(new Symbiont(random, world, &config, int_val) );
}

TEST_CASE("SetIntVal, GetIntVal", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    double int_val = -1;
    Symbiont * s = new Symbiont(random, world, &config, int_val);

    int_val = -2;
    REQUIRE_THROWS( s->SetIntVal(int_val) );

    int_val = -1;
    Symbiont * s2 = new Symbiont(random, world, &config, int_val);

    int_val = 1;
    s2->SetIntVal(int_val);
    double orig_int_val = 1;

    REQUIRE(s2->GetIntVal() == orig_int_val);

    int_val = -1;
    Symbiont * s3 = new Symbiont(random, world, &config, int_val);

    int_val = 2;
    REQUIRE_THROWS( s3->SetIntVal(int_val) ) ;

    int_val = 0;
    Symbiont * s4 = new Symbiont(random, world, &config, int_val);

    int_val = -1;
    s4->SetIntVal(int_val);
    orig_int_val = -1;

    REQUIRE( s4->GetIntVal() == orig_int_val) ;

}

TEST_CASE("SetInfectionChance, GetInfectionChance", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    double int_val = -1;
    Symbiont * sym = new Symbiont(random, world, &config, int_val);

    double infection_chance = -1;
    REQUIRE_THROWS( sym->SetInfectionChance(infection_chance));

    double orig_infection_chance = 0;
    sym->SetInfectionChance(orig_infection_chance);
    REQUIRE(sym->GetInfectionChance() == orig_infection_chance);

    double new_infection_chance = 1;
    sym->SetInfectionChance(new_infection_chance);
    REQUIRE(sym->GetInfectionChance() == new_infection_chance);

    infection_chance = 2;
    REQUIRE_THROWS(sym->SetInfectionChance(infection_chance));
}

TEST_CASE("SetPoints, GetPoints", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    double int_val = -1;
    Symbiont * s = new Symbiont(random, world, &config, int_val);

    int points = 1;
    s->SetPoints(points);
    double orig_points = 1;

    REQUIRE( s->GetPoints() == orig_points);

    int add_points = -1;
    s->AddPoints(add_points);
    orig_points = 0;

    REQUIRE( s->GetPoints() == orig_points);

    add_points = 150;
    s->AddPoints(add_points);
    orig_points = 150;

    REQUIRE(s->GetPoints() == orig_points);
}

TEST_CASE("Symbiont SetDead, GetDead", "[default]"){
    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    double int_val = -1;
    Symbiont * s = new Symbiont(random, world, &config, int_val);

    //new symbionts are alive until specified otherwise
    bool expected_dead = false;
    REQUIRE(s->GetDead() == expected_dead);

    //verify that setting it to dead means that death is set to true
    expected_dead = true;
    s->SetDead();
    REQUIRE(s->GetDead() == expected_dead);
}

TEST_CASE("WantsToInfect", "[default]"){
    emp::Ptr<emp::Random> random = new emp::Random(17);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;
    double int_val = 0;

    WHEN("sym infection chance is 0"){
        config.SYM_INFECTION_CHANCE(0);
        Symbiont * sym1 = new Symbiont(random, world, &config, int_val);
        Symbiont * sym2 = new Symbiont(random, world, &config, int_val);

        THEN("syms never want to infect"){
            REQUIRE(sym1->WantsToInfect() == false);
            REQUIRE(sym2->WantsToInfect() == false);
        }
    }

    WHEN("sym infection chance is 1"){
        config.SYM_INFECTION_CHANCE(1);
        Symbiont * sym1 = new Symbiont(random, world, &config, int_val);
        Symbiont * sym2 = new Symbiont(random, world, &config, int_val);

        THEN("syms always want to infect"){
            REQUIRE(sym1->WantsToInfect() == true);
            REQUIRE(sym2->WantsToInfect() == true);
        }
    }
}

TEST_CASE("InfectionFails", "[default]"){
    emp::Ptr<emp::Random> random = new emp::Random(17);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;
    double int_val = 0;

    WHEN("sym infection failure rate is 0"){
        config.SYM_INFECTION_FAILURE_RATE(0);
        Symbiont * sym1 = new Symbiont(random, world, &config, int_val);
        Symbiont * sym2 = new Symbiont(random, world, &config, int_val);

        THEN("infection never fails"){
            REQUIRE(sym1->InfectionFails() == false);
            REQUIRE(sym2->InfectionFails() == false);
        }
    }

    WHEN("sym infection failure rate is between 0 and 1"){
        config.SYM_INFECTION_FAILURE_RATE(0.5);
        emp::Ptr<Organism> s1 = new Symbiont(random, world, &config, int_val);
        emp::Ptr<Organism> s2 = new Symbiont(random, world, &config, int_val);
        emp::Ptr<Organism> s3 = new Symbiont(random, world, &config, int_val);
        emp::Ptr<Organism> s4 = new Symbiont(random, world, &config, int_val);
        size_t failed_infection_count = 0;
        size_t total_possible = 4;

        if(s1->InfectionFails() == true) failed_infection_count = failed_infection_count + 1;
        if(s2->InfectionFails() == true) failed_infection_count = failed_infection_count + 1;
        if(s3->InfectionFails() == true) failed_infection_count = failed_infection_count + 1;
        if(s4->InfectionFails() == true) failed_infection_count = failed_infection_count + 1;

        THEN("infection sometimes fails, sometimes doesn't"){
            REQUIRE(failed_infection_count < total_possible);
            REQUIRE(failed_infection_count > 0);
        }
    }

    WHEN("sym infection failure rate is 1"){
        config.SYM_INFECTION_FAILURE_RATE(1);
        Symbiont * sym1 = new Symbiont(random, world, &config, int_val);
        Symbiont * sym2 = new Symbiont(random, world, &config, int_val);

        THEN("infection always fails"){
            REQUIRE(sym1->InfectionFails() == true);
            REQUIRE(sym2->InfectionFails() == true);
        }
    }
}

TEST_CASE("mutate", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(37);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    WHEN("Mutation rate is not zero") {
        double int_val = 0;
        double orig_infection_chance = 1;
        config.MUTATION_SIZE(0.002);

        WHEN("free living symbionts are allowed"){
            config.FREE_LIVING_SYMS(1);
            config.SYM_INFECTION_CHANCE(orig_infection_chance);
            Symbiont * s = new Symbiont(random, world, &config, int_val);
            s->mutate();

            THEN("Mutation occurs and both interaction value and infection chance change"){
                REQUIRE(s->GetIntVal() != int_val);
                REQUIRE(s->GetIntVal() <= 1);
                REQUIRE(s->GetIntVal() >= -1);
                REQUIRE(s->GetInfectionChance() != orig_infection_chance);
                REQUIRE(s->GetInfectionChance() >= 0);
                REQUIRE(s->GetInfectionChance() <= 1);
            }
        }

        WHEN("free living symbionts are not allowed"){
            Symbiont * s = new Symbiont(random, world, &config, int_val);
            s->mutate();

            THEN("Mutation occurs and only interaction value changes") {
                REQUIRE(s->GetIntVal() != int_val);
                REQUIRE(s->GetIntVal() <= 1);
                REQUIRE(s->GetIntVal() >= -1);
            }
        }
    }


    WHEN("Mutation rate is zero") {
        double int_val = 1;
        int orig_int_val = 1;
        double points = 0.0;
        config.SYM_HORIZ_TRANS_RES(100.0);
        config.HORIZ_TRANS(true);
        config.MUTATION_RATE(0);
        config.MUTATION_SIZE(0);
        Symbiont * s = new Symbiont(random, world, &config, int_val, points);

        s->mutate();


        THEN("Mutation does not occur and interaction value does not change") {
            REQUIRE(s->GetIntVal() == orig_int_val);
        }
    }
}

TEST_CASE("reproduce", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(3);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;


    WHEN("Mutation rate is zero")  {
        double int_val = 0;
        double inf_chance = 0.5;
        double parent_orig_inf_chance = 0.5;
        double parent_orig_int_val = 0;
        double points = 0.0;
        config.SYM_HORIZ_TRANS_RES(100.0);
        config.HORIZ_TRANS(true);
        config.MUTATION_SIZE(0);
        config.FREE_LIVING_SYMS(1);
        config.SYM_INFECTION_CHANCE(inf_chance);
        Symbiont * s = new Symbiont(random, world, &config, int_val, points);
        s->SetAge(10);

        emp::Ptr<Organism> sym_baby = s->reproduce();


        THEN("Offspring's interaction value equals parent's interaction value") {
            double sym_baby_int_val = 0;
            REQUIRE( sym_baby->GetIntVal() == sym_baby_int_val);
            REQUIRE( sym_baby->GetIntVal() == parent_orig_int_val);
            REQUIRE( s->GetIntVal() == parent_orig_int_val);
        }

        THEN("Offspring's infection chance equals parent's infection chance") {
            double sym_baby_inf_chance = 0.5;
            REQUIRE( sym_baby->GetInfectionChance() == sym_baby_inf_chance);
            REQUIRE( sym_baby->GetInfectionChance() == parent_orig_inf_chance);
            REQUIRE( s->GetInfectionChance() == parent_orig_inf_chance);
        }

        THEN("Offspring's points are zero") {
            int sym_baby_points = 0;
            REQUIRE( sym_baby->GetPoints() == sym_baby_points);

        }

        THEN("Offspring's age is 0") {
            REQUIRE(sym_baby->GetAge() == 0);
        }

        sym_baby.Delete();
    }


    WHEN("Mutation rate is not zero") {
        double int_val = 0;
        double inf_chance = 0.5;
        double parent_orig_inf_chance = 0.5;
        double parent_orig_int_val = 0;
        double points = 0.0;
        config.SYM_HORIZ_TRANS_RES(100.0);
        config.HORIZ_TRANS(true);
        config.MUTATION_SIZE(0.01);
        config.FREE_LIVING_SYMS(1);
        config.SYM_INFECTION_CHANCE(inf_chance);
        Symbiont * s2 = new Symbiont(random, world, &config, int_val, points);

        emp::Ptr<Organism> sym_baby = s2->reproduce();


        THEN("Offspring's interaction value does not equal parent's interaction value") {
            REQUIRE(sym_baby->GetIntVal() != parent_orig_int_val);
            REQUIRE(sym_baby->GetIntVal() <= 1);
            REQUIRE(sym_baby->GetIntVal() >= -1);
            REQUIRE(s2->GetIntVal() == parent_orig_int_val);
        }

        THEN("Offspring's infection chance does not equal parent's infection chance") {
            REQUIRE( sym_baby->GetInfectionChance() != parent_orig_inf_chance);
            REQUIRE( sym_baby->GetInfectionChance() <= 1);
            REQUIRE( sym_baby->GetInfectionChance() >= -1);
            REQUIRE( s2->GetInfectionChance() == parent_orig_inf_chance);
        }

        THEN("Offspring's points are zero") {
            int sym_baby_points = 0;
            REQUIRE( sym_baby->GetPoints() == sym_baby_points);

        }

        THEN("Offspring's age is 0") {
            REQUIRE(sym_baby->GetAge() == 0);
        }

        sym_baby.Delete();
    }

}

TEST_CASE("Process", "[default]") {

    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld w(*random);
    SymWorld * world = &w;

    //add new test for free living sym not moving when it shouldnt
    WHEN("Horizontal transmission is true and points is greater than sym_h_res") {
        double int_val = 1;
        // double parent_orig_int_val = 1;
        double points = 0.0;
        config.SYM_HORIZ_TRANS_RES(140.0);
        config.HORIZ_TRANS(true);
        config.MUTATION_SIZE(0);
        Symbiont * s = new Symbiont(random, world, &config, int_val, points);

        int add_points = 200;
        s->AddPoints(add_points);

        int location = 10;
        s->Process(location);


        THEN("Points changes and is set to 0") {
            int points_post_reproduction = 0;
            REQUIRE(s->GetPoints() == points_post_reproduction);
        }
    }


    WHEN("Horizontal transmission is true and points is less than sym_h_res") {
        double int_val = 1;
        // double parent_orig_int_val = 1;
        double points = 0.0;
        config.SYM_HORIZ_TRANS_RES(200.0);
        config.HORIZ_TRANS(true);
        config.MUTATION_SIZE(0.0);
        Symbiont * s = new Symbiont(random, world, &config, int_val, points);

        int add_points = 50;
        s->AddPoints(add_points);

        int location = 10;
        s->Process(location);


        THEN("Points does not change") {
            int points_post_reproduction = 50;
            REQUIRE(s->GetPoints() == points_post_reproduction);
        }
    }


    WHEN("Horizontal transmission is false and points and points is greater then sym_h_res") {
        double int_val = 1;
        // double parent_orig_int_val = 1;
        double points = 100.0;
        config.SYM_HORIZ_TRANS_RES(80.0);
        config.HORIZ_TRANS(false);
        config.MUTATION_SIZE(0.0);
        Symbiont * s = new Symbiont(random, world, &config, int_val, points);

        int location = 10;
        s->Process(location);


        THEN("Points does not change") {
            int points_post_reproduction = 100;
            REQUIRE(s->GetPoints() == points_post_reproduction);
        }
    }

    WHEN("Horizontal transmission is false and points and points is less then sym_h_res") {
        double int_val = 1;
        // double parent_orig_int_val = 1;
        double points = 40.0;
        config.SYM_HORIZ_TRANS_RES(80.0);
        config.HORIZ_TRANS(false);
        config.MUTATION_SIZE(0.0);
        Symbiont * s = new Symbiont(random, world, &config, int_val, points);

        int location = 10;
        s->Process(location);


        THEN("Points does not change") {
            int points_post_reproduction = 40;
            REQUIRE(s->GetPoints() == points_post_reproduction);
        }
    }

}

TEST_CASE("Symbiont ProcessResources", "[default]"){
   emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymWorld w(*random);
    SymWorld * world = &w;
    SymConfigBase config;
    config.SYNERGY(5);


    WHEN("sym_int_val < 0"){
        double sym_int_val = -0.6;

        WHEN("host_int_val > 0"){
            double host_int_val = 0.2;
            Host * h = new Host(random, &w, &config, host_int_val);
            Symbiont * s = new Symbiont(random, world, &config, sym_int_val);
            h->AddSymbiont(s);

            // double resources = 100;
            // double hostDonation = 20;
            // double stolen = 48;
            double expected_sym_points = 68; // hostDonation + stolen
            double expected_return = 0; // hostportion * synergy

            h->SetResInProcess(80);

            THEN("sym receives a donation and stolen resources, host receives betrayal"){
                REQUIRE(s->ProcessResources(20) == expected_return);
                REQUIRE(s->GetPoints() == expected_sym_points);

            }
        }

        WHEN("host_int_val < 0 and resources are placed into defense"){

            WHEN("host successfully defends from symsteal"){
                double host_int_val = -0.8;
                Host * h = new Host(random, &w, &config, host_int_val);
                Symbiont * s = new Symbiont(random, world, &config, sym_int_val);
                h->AddSymbiont(s);

                // double resources = 100;
                // double hostDonation = 0;
                // double stolen = 0;
                // double hostDefense = 80;
                double expected_sym_points = 0; // hostDonation + stolen
                double expected_return = 0; // hostportion * synergy

                h->SetResInProcess(20);
                THEN("symbiont is unsuccessful at stealing"){
                    REQUIRE(s->ProcessResources(0) == expected_return);
                    REQUIRE(s->GetPoints() == expected_sym_points);
                }
            }

            WHEN("host fails at defense"){
                double host_int_val = -0.5;
                Host * h = new Host(random, &w, &config, host_int_val);
                Symbiont * s = new Symbiont(random, world, &config, sym_int_val);
                h->AddSymbiont(s);

                // double resources = 100;
                // double hostDonation = 0;
                // double stolen = 5;
                // double hostDefense = 50;
                double expected_sym_points = 5; // hostDonation + stolen
                double expected_return = 0; // hostportion * synergy

                h->SetResInProcess(50);

                THEN("Sym steals successfully"){
                    REQUIRE(s->ProcessResources(0) == expected_return);
                    REQUIRE(s->GetPoints() == Approx(expected_sym_points));
                }
            }

        }

    }

    WHEN("sym_int_val > 0") {
        double sym_int_val = 0.2;
        double host_int_val = 0.5;
        Host * h = new Host(random, &w, &config, host_int_val);
        Symbiont * s = new Symbiont(random, world, &config, sym_int_val);
        h->AddSymbiont(s);

        // double resources = 100;
        // double hostDonation = 50;
        // double hostPortion = 10; hostDonation * sym_int_val
        double expected_sym_points = 40; // hostDonation - hostPortion
        double expected_return = 50; // hostPortion * synergy

        h->SetResInProcess(50);


        THEN("Sym attempts to give benefit back"){
            REQUIRE(s->ProcessResources(50) == expected_return);
            REQUIRE(s->GetPoints() == expected_sym_points);
        }
    }

}

TEST_CASE("Symbiont GrowOlder", "[default]"){
    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymWorld w(*random);
    w.Resize(2,2);
    SymConfigBase config;
    config.SYM_AGE_MAX(2);

    WHEN ("A free-living symbiont reaches its maximum age"){
      config.FREE_LIVING_SYMS(1);
      Symbiont * s = new Symbiont(random, &w, &config, 1);
      w.AddOrgAt(s, 1);
      THEN("The symbiont dies and gets removed from the world"){
        REQUIRE(w.GetNumOrgs() == 1);
        REQUIRE(s->GetDead() == false);
        REQUIRE(s->GetAge() == 0);
        w.Update(); //sym goes from age 1->2
        REQUIRE(s->GetAge() == 1);
        w.Update();
        REQUIRE(s->GetAge() == 2);
        w.Update(); //sym goes from age 2->3, gets set to dead
        w.Update(); //sym is deleted (before it can process)
        REQUIRE(w.GetNumOrgs() == 0);
      }
    }
    WHEN ("A hosted symbiont reaches its maximum age"){
      Symbiont * s = new Symbiont(random, &w, &config, 1);
      Host * h = new Host(random, &w, &config, 1);
      w.AddOrgAt(h, 1);
      h->AddSymbiont(s);
      THEN("It dies and gets removed from its host"){
        REQUIRE(h->HasSym() == true);
        REQUIRE(s->GetAge() == 0);
        h->Process(1);
        REQUIRE(s->GetAge() == 1);
        h->Process(1);
        REQUIRE(h->HasSym() == true);
        REQUIRE(s->GetAge() == 2);
        h->Process(1); //should now be dead and removed
        REQUIRE(h->HasSym() == false);
      }
    }
}

TEST_CASE("Symbiont makeNew", "[default]"){
    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymWorld w(*random);
    SymConfigBase config;

    double sym_int_val = 0.2;
    Organism * s1 = new Symbiont(random, &w, &config, sym_int_val);
    Organism * s2 = s1->makeNew();

    THEN("The new symbiont has the same genome as its parent, but age and points 0"){
        REQUIRE(s2->GetIntVal() == s1->GetIntVal());
        REQUIRE(s2->GetInfectionChance() == s1->GetInfectionChance());
        REQUIRE(s2->GetAge() == 0);
        REQUIRE(s2->GetPoints() == 0);
        //check that the offspring is the correct class
        REQUIRE(typeid(*s2).name() == typeid(*s1).name());
    }
}