Program Listing for File HostSymbiontUnitTest.test.cc

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

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

TEST_CASE("Symbiont SetHost, GetHost", "[default]") {

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

    emp::Ptr<Organism> host = emp::NewPtr<Host>(random, &world, &config);
    emp::Ptr<Symbiont> symbiont = emp::NewPtr<Symbiont>(random, &world, &config, int_val);

    symbiont->SetHost(host);

    REQUIRE(symbiont->GetHost() == host);

    symbiont.Delete();
    host.Delete();
}

TEST_CASE("Host SetSymbionts", "[default]") {
    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    SymWorld world(*random, &config);
    double int_val = 1;
    config.SYM_LIMIT(2);

    emp::Ptr<Organism> host = emp::NewPtr<Host>(random, &world, &config);
    emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, int_val);
    emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, int_val);

    emp::vector<emp::Ptr<Organism>> syms;
    syms.push_back(sym1);
    syms.push_back(sym2);

    host->SetSymbionts(syms);

    REQUIRE(host->GetSymbionts().size() == syms.size());

    for(size_t i = 0; i < syms.size(); i++){
        emp::vector<emp::Ptr<Organism>> host_syms = host->GetSymbionts();
        emp::Ptr<Organism> curSym = host_syms[i];
        emp::Ptr<Organism> curHost = curSym->GetHost();
        REQUIRE(curSym == (emp::Ptr<Organism>) syms[i]);
        REQUIRE(curHost == host);
    }

    bool has_sym = true;
    REQUIRE(host->HasSym() == has_sym);

    host.Delete();
}

TEST_CASE("Host SymLimit", "[default]") {
    emp::Ptr<emp::Random> random;
    random.New(-1);
    SymConfigBase config;
    SymWorld world(*random, &config);
    double int_val = 1;

    emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config);

    emp::Ptr<Symbiont> sym1;
    sym1.New(random, &world, &config, int_val);
    emp::Ptr<Symbiont> sym2;
    sym2.New(random, &world, &config, int_val);

    emp::vector<emp::Ptr<Organism>> syms;

    syms.push_back(sym1);
    host->AddSymbiont(sym1);
    REQUIRE(host->GetSymbionts() == syms);

    WHEN("A symbiont is added once the SymLimit has been reached ") {
        host->AddSymbiont(sym2);

        THEN("The symbiont is not added to the host's syms") {
            REQUIRE(host->GetSymbionts() == syms); // sym2 is not added, sym limit was reached

        }

    }
    random.Delete();
    host.Delete();
}

TEST_CASE("Host AddSymbiont", "[default]") {
    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    config.SYM_LIMIT(6);
    SymWorld world(*random, &config);
    double int_val = 1;

    emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config);

    emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, int_val);
    emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, int_val);

    emp::vector<emp::Ptr<Organism>> syms;

    syms.push_back(sym1);
    host->AddSymbiont(sym1);

    REQUIRE(host->GetSymbionts() == syms);
    bool has_sym = true;
    REQUIRE(host->HasSym() == has_sym);

    host->AddSymbiont(sym2);
    syms.push_back(sym2);
    REQUIRE(host->GetSymbionts() == syms);

    host.Delete();
}

TEST_CASE("Host AddReproSym, ClearReproSym, GetReproSymbionts", "[default]") {
    emp::Ptr<emp::Random> random = new emp::Random(-1);
    SymConfigBase config;
    config.SYM_LIMIT(6);
    SymWorld world(*random, &config);
    double int_val = 1;

    emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config);

    emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, int_val);
    emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, int_val);

    emp::vector<emp::Ptr<Organism>> repro_syms;

    repro_syms.push_back(sym1);
    host->AddReproSym(sym1);

    REQUIRE(host->GetReproSymbionts() == repro_syms);

    repro_syms.push_back(sym2);
    host->AddReproSym(sym2);

    REQUIRE(host->GetReproSymbionts() == repro_syms);

    host->ClearReproSyms();
    repro_syms.clear();
    REQUIRE(host->GetReproSymbionts() == repro_syms);

    host.Delete();
    sym1.Delete();
    sym2.Delete();
}

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

    WHEN("Host interaction value >= 0 and  Symbiont interaction value >= 0") {

        double host_int_val = 0.5;
        double sym_int_val = 1;

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config, host_int_val);


        emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
        emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
        emp::Ptr<Symbiont> sym3 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
        emp::vector<emp::Ptr<Organism>> syms = {sym1, sym2, sym3};
        host->SetSymbionts(syms);

        double resources = 120;
        host->DistribResources(resources);


        int num_syms = 3;
        double sym_piece = resources / num_syms; // how much resource each sym gets
        double host_donation = sym_piece * host_int_val;
        double host_portion = sym_piece - host_donation;
        double sym_return = (host_donation * sym_int_val) * config.SYNERGY();
        double sym_portion = host_donation - (host_donation * sym_int_val);
        host_portion += sym_return;

        double host_points = num_syms * host_portion; // * by num_syms bc points are added during each iteration through host's syms
        double sym_points = sym_portion;


        THEN("Host and Symbionts points increase") {

            for( emp::Ptr<Organism> symbiont : syms) {
                REQUIRE(symbiont->GetPoints() == sym_points);
            }
            REQUIRE(host->GetPoints() == host_points);
        }
        host.Delete();
    }


    WHEN("Host interaction value <= 0 and Symbiont interaction value < 0") {

        WHEN("Host interaction value < Symbionts' interaction value") {
            double host_int_val = -0.5;
            double sym_int_val = -0.1;
            double host_orig_points = 0;
            double sym_orig_points = 0;

            emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config, host_int_val);


            emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
            emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
            emp::Ptr<Symbiont> sym3 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
            emp::vector<emp::Ptr<Organism>> syms = {sym1, sym2, sym3};
            host->SetSymbionts(syms);

            double resources = 120;
            host->DistribResources(resources);

            int num_syms = 3;
            double sym_piece = resources / num_syms; // how much resource each sym gets
            double host_defense = -1 * (host_int_val * sym_piece);
            double remaining_resources = sym_piece - host_defense;
            double host_points = remaining_resources * num_syms; // * by num_syms bc points are added during each iteration through host's syms

            THEN("Symbiont points do not change (gets nothing from host), Host points increase") {
                for( emp::Ptr<Organism> symbiont : syms) {
                    REQUIRE(symbiont->GetPoints() == sym_orig_points);
                }
                REQUIRE(host->GetPoints() == host_points);
                REQUIRE(host->GetPoints() > host_orig_points);
            }
            host.Delete();
        }

        WHEN("Host interaction value > Symbionts' interaction value") {
            double host_int_val = -0.2;
            double sym_int_val = -0.6;
            double host_orig_points = 0;
            double sym_orig_points = 0;

            emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config, host_int_val);


            emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
            emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
            emp::Ptr<Symbiont> sym3 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
            emp::vector<emp::Ptr<Organism>> syms = {sym1, sym2, sym3};
            host->SetSymbionts(syms);

            double resources = 120;
            host->DistribResources(resources);

            int num_syms = 3;
            double sym_piece = resources / num_syms; // how much resource each sym gets
            double host_defense = -1 * (host_int_val * sym_piece);
            double remaining_resources = sym_piece - host_defense;
            double sym_steals = (host_int_val - sym_int_val) * remaining_resources;
            double sym_points = sym_steals;
            double host_points = (remaining_resources - sym_steals) * num_syms; // * by num_syms bc points are added during each iteration through host's syms

            THEN("Symbionts points and Host points increase") {
                for( emp::Ptr<Organism> symbiont : syms) {
                    REQUIRE(symbiont->GetPoints() == sym_points);
                    REQUIRE(symbiont->GetPoints() > sym_orig_points);
                }
                REQUIRE(host->GetPoints() == host_points);
                REQUIRE(host->GetPoints() > host_orig_points);
            }
            host.Delete();
        }
    }
    WHEN("Host interaction value > 0 and Symbiont interaction value < 0, single symbiont") {
        double host_int_val = 0.1;
        double sym_int_val = -0.1;
        double host_orig_points = 0;
        double sym_orig_points = 0;

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config, host_int_val);
        emp::Ptr<Symbiont> symbiont = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val, sym_orig_points);
        host->AddSymbiont(symbiont);

        int resources = 100;
        host->DistribResources(resources);

        // int host_donation = 10; //host_int_val * resources
        int host_portion = 90;  //remaining amount
        int sym_steals = 9; //host_portion * sym_int_val * -1; new code value should be 18
        int sym_portion = 19; //sym_steals + host_donation; new code value should be 28
        host_portion = host_portion - sym_steals; //remove stolen resources from host's portion

        THEN("Symbionts points and Host points increase the correct amounts") {
            REQUIRE(symbiont->GetPoints() == sym_orig_points+sym_portion);
            REQUIRE(host->GetPoints() == host_orig_points+host_portion);
        }
        host.Delete();
    }
    WHEN("Host interaction value > 0 and Symbiont interaction value < 0, multiple symbionts") {
        double host_int_val = 0.1;
        double sym_int_val = -0.1;
        double host_orig_points = 0;
        double sym_orig_points = 0;

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config, host_int_val);


        emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val, sym_orig_points);
        emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val, sym_orig_points);
        emp::Ptr<Symbiont> sym3 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val, sym_orig_points);
        emp::vector<emp::Ptr<Organism>> syms = {sym1, sym2, sym3};
        host->SetSymbionts(syms);

        double resources = 120;
        host->DistribResources(resources);


        int num_syms = 3;
        // double sym_piece = 40; //resources / num_syms

        // int host_donation = 4; //host_int_val * sym_piece
        double host_portion = 36;  //remaining amount
        double sym_steals = 3.6; //host_portion * sym_int_val * -1
        double sym_portion = 7.6; //sym_steals + host_donation
        host_portion = host_portion - sym_steals; //remove stolen resources from host's portion

        double host_final_portion = host_portion * num_syms;


       THEN("Symbionts points and Host points increase") {
           for( emp::Ptr<Organism> symbiont : syms) {


               REQUIRE(symbiont->GetPoints() == sym_portion);
               REQUIRE(symbiont->GetPoints() > sym_orig_points);
            }

            REQUIRE(host->GetPoints() == host_final_portion);
            REQUIRE(host->GetPoints() > host_orig_points);
        }
        host.Delete();
    }


    WHEN("Host interaction value < 0 and Symbiont interaction value >= 0") {
        double host_int_val = -0.1;
        double sym_int_val = 0.8;
        double host_orig_points = 0;
        double symbiont_orig_points = 0;

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, &world, &config, host_int_val);


        emp::Ptr<Symbiont> sym1 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
        emp::Ptr<Symbiont> sym2 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
        emp::Ptr<Symbiont> sym3 = emp::NewPtr<Symbiont>(random, &world, &config, sym_int_val);
        emp::vector<emp::Ptr<Organism>> syms = {sym1, sym2, sym3};
        host->SetSymbionts(syms);

        double resources = 120;
        host->DistribResources(resources);

        int num_syms = 3;
        double sym_piece = resources / num_syms;
        double host_defense = -1 * (host_int_val * sym_piece);
        double host_portion = sym_piece - host_defense;
        double sym_portion = 0;

        double sym_points = sym_portion;
        double host_points = host_portion * num_syms; // * by num_syms bc points are added during each iteration through host's syms

        THEN("Symbiont points do not change (gets nothing from host), Host points increase") {
            for( emp::Ptr<Organism> symbiont : syms) {
                REQUIRE(symbiont->GetPoints() == sym_points);
                REQUIRE(symbiont->GetPoints() == symbiont_orig_points);
            }
            REQUIRE(host->GetPoints() == host_points);
            REQUIRE(host->GetPoints() > host_orig_points);

        }
        host.Delete();
    }
}

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



    WHEN("When vertical transmission is enabled and the sym has enough resources to transmit"){
        config.VERTICAL_TRANSMISSION(1);
        double points_required = 50;
        double points_recieved = points_required;
        config.SYM_VERT_TRANS_RES(points_required);
        double host_int_val = .5;
        double sym_int_val = -.5;

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, world, &config, host_int_val);
        emp::Ptr<Symbiont> symbiont = emp::NewPtr<Symbiont>(random, world, &config, sym_int_val);
        symbiont->AddPoints(points_recieved);

        emp::Ptr<Host> host_baby = emp::NewPtr<Host>(random, world, &config, host->GetIntVal());
        long unsigned int expected_sym_size = host_baby->GetSymbionts().size() + 1;
        symbiont->VerticalTransmission(host_baby);

        THEN("Symbiont offspring are injected into host offspring") {
            REQUIRE(host_baby->GetSymbionts().size() == expected_sym_size);
        }

        THEN("Symbiont parent has lost the points needed for reproduction and is down to 0") {
            REQUIRE(symbiont->GetPoints() == 0);
        }
        symbiont.Delete();
        host.Delete();
        host_baby.Delete();
    }
    WHEN("When vertical transmission is disabled"){
        config.VERTICAL_TRANSMISSION(0);
        double host_int_val = .5;
        double sym_int_val = -.5;

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, world, &config, host_int_val);
        emp::Ptr<Symbiont> symbiont = emp::NewPtr<Symbiont>(random, world, &config, sym_int_val);

        emp::Ptr<Host> host_baby = emp::NewPtr<Host>(random, world, &config, host->GetIntVal());
        long unsigned int expected_sym_size = host_baby->GetSymbionts().size();
        symbiont->VerticalTransmission(host_baby);

        THEN("Symbiont offspring are not injected into host offspring") {
            REQUIRE(host_baby->GetSymbionts().size() == expected_sym_size);
        }
        symbiont.Delete();
        host.Delete();
        host_baby.Delete();
    }
    WHEN("When the sym does not have enough resources to transmit"){
        config.VERTICAL_TRANSMISSION(1);
        double int_val = 0;
        double points_required = 50;
        double points_recieved = points_required - 1;
        config.SYM_VERT_TRANS_RES(points_required);

        emp::Ptr<Host> host = emp::NewPtr<Host>(random, world, &config, int_val);
        emp::Ptr<Symbiont> symbiont = emp::NewPtr<Symbiont>(random, world, &config, int_val);

        symbiont->AddPoints(points_recieved);

        emp::Ptr<Host> host_baby = emp::NewPtr<Host>(random, world, &config, host->GetIntVal());
        long unsigned int expected_sym_size = host_baby->GetSymbionts().size();
        symbiont->VerticalTransmission(host_baby);

        THEN("Symbiont offspring are not injected into host offspring") {
            REQUIRE(host_baby->GetSymbionts().size() == expected_sym_size);
        }

        symbiont.Delete();
        host.Delete();
        host_baby.Delete();
    }
}

TEST_CASE("HandleEctosymbiosis"){
  emp::Random random(17);
  SymConfigBase config;
  SymWorld world(random, &config);
  world.Resize(1,1);
  double int_val = 0.5;

  config.FREE_LIVING_SYMS(1);
  config.SYM_INFECTION_CHANCE(0.0);

  WHEN("Ectosymbiosis is off"){
    config.ECTOSYMBIOSIS(0);

    emp::Ptr<Host> host = emp::NewPtr<Host>(&random, &world, &config, int_val);
    emp::Ptr<Organism> sym = emp::NewPtr<Symbiont>(&random, &world, &config, int_val);
    world.AddOrgAt(sym,0);
    world.AddOrgAt(host,0);
    REQUIRE(sym->GetPoints() == 0);
    REQUIRE(host->GetPoints() == 0);

    double res = 10;
    double sym_res = 0;
    double host_res = res * int_val;

    double leftover_res = host->HandleEctosymbiosis(res, 0);
    host->DistribResources(leftover_res);

    THEN("Parallel organisms don't distribute resources together"){
      REQUIRE(sym->GetPoints() == sym_res);
      REQUIRE(host->GetPoints() == host_res);
      REQUIRE(leftover_res == res);
    }
  }
  WHEN("Ectosymbiosis is on"){
    config.ECTOSYMBIOSIS(1);

    WHEN("There is no endosymbiont, only ectosymbiont"){
      emp::Ptr<Host> host = emp::NewPtr<Host>(&random, &world, &config, int_val);
      emp::Ptr<Organism> sym = emp::NewPtr<Symbiont>(&random, &world, &config, int_val);

      world.AddOrgAt(sym,0);
      world.AddOrgAt(host,0);

      REQUIRE(sym->GetPoints() == 0);
      REQUIRE(host->GetPoints() == 0);

      double res = 10;
      int synergy = 5;

      double host_res = (res * int_val) + (res * int_val * int_val * synergy); //host portion + sym donation
      double sym_res = res * int_val * int_val;

      double leftover_res = host->HandleEctosymbiosis(res, 0);

      THEN("Ecto symbiont benefits fully"){
        REQUIRE(sym->GetPoints() == sym_res);
        REQUIRE(host->GetPoints() == host_res);
        REQUIRE(leftover_res == 0);
      }
    }

    WHEN("A hosted sym does not confer immunity to ectosymbiosis"){
      int synergy = 1;
      config.ECTOSYMBIOTIC_IMMUNITY(0);
      config.SYNERGY(synergy);

      emp::Ptr<Host> host = emp::NewPtr<Host>(&random, &world, &config, int_val);
      emp::Ptr<Organism> parallel_sym = emp::NewPtr<Symbiont>(&random, &world, &config, int_val);
      emp::Ptr<Organism> hosted_sym = emp::NewPtr<Symbiont>(&random, &world, &config, int_val);

      world.AddOrgAt(parallel_sym,0);
      world.AddOrgAt(host,0);
      host->AddSymbiont(hosted_sym);

      REQUIRE(parallel_sym->GetPoints() == 0);
      REQUIRE(hosted_sym->GetPoints() == 0);
      REQUIRE(host->GetPoints() == 0);

      double res = 10;

      double host_res = (res * int_val) + (res * int_val * int_val * synergy); //host portion + sym donation
      //10 res, sym portion is 5, host with interaction val of .5 keeps 2.5 of each sym piece
      //each sym keeps 1.25 of a piece, and donates 1.25 back, meaning the host gets 7.5 total
      double sym_res = (res/2 * int_val * int_val); //syms

      double leftover_res = host->HandleEctosymbiosis(res, 0);
      host->DistribResources(leftover_res);

      THEN("Both symbionts get the same amount of resources"){
        REQUIRE(hosted_sym->GetPoints() == sym_res);
        REQUIRE(parallel_sym->GetPoints() == sym_res);
        REQUIRE(host->GetPoints() == host_res);
        REQUIRE(leftover_res == (res/2)); //resources are split between two syms
      }
    }

    WHEN("A hosted sym confers immunity to ectosymbiosis"){
      config.ECTOSYMBIOTIC_IMMUNITY(1);

      emp::Ptr<Host> host = emp::NewPtr<Host>(&random, &world, &config, int_val);
      emp::Ptr<Organism> parallel_sym = emp::NewPtr<Symbiont>(&random, &world, &config, int_val);
      emp::Ptr<Organism> hosted_sym = emp::NewPtr<Symbiont>(&random, &world, &config, int_val);

      world.AddOrgAt(parallel_sym,0);
      world.AddOrgAt(host,0);
      host->AddSymbiont(hosted_sym);

      REQUIRE(parallel_sym->GetPoints() == 0);
      REQUIRE(hosted_sym->GetPoints() == 0);
      REQUIRE(host->GetPoints() == 0);

      double res = 10;
      int synergy = 5;

      double host_res = (res * int_val) + (res * int_val * int_val * synergy); //host portion + sym donation
      double hosted_sym_res = res * int_val * int_val;

      double leftover_res = host->HandleEctosymbiosis(res, 0);
      host->DistribResources(leftover_res);

      THEN("The parallel symbiont does not recieve resources"){
        REQUIRE(hosted_sym->GetPoints() == hosted_sym_res);
        REQUIRE(parallel_sym->GetPoints() == 0);
        REQUIRE(host->GetPoints() == host_res);
        REQUIRE(leftover_res == res); //ectosymbiosis doesn't happen
      }
    }
    WHEN("There is no parallel sym"){
      double int_val = 0.5;

      config.ECTOSYMBIOSIS(1);

      emp::Ptr<Host> host = emp::NewPtr<Host>(&random, &world, &config, int_val);
      world.AddOrgAt(host,0);
      REQUIRE(host->GetPoints() == 0);

      double res = 10;
      double host_res = res * int_val;

      double leftover_res = host->HandleEctosymbiosis(res, 0);
      host->DistribResources(leftover_res);

      THEN("The host does not get a sym modifier on its resources"){
        REQUIRE(host->GetPoints() == host_res);
        REQUIRE(leftover_res == res);
      }
    }
  }
}