Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions tests/models/animals/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,39 @@ def herbivore_cohort_instance(
)


@pytest.fixture
def fungivore_functional_group_instance(shared_datadir, constants_instance):
"""Fixture for an animal functional group used in tests."""
from virtual_ecosystem.models.animal.functional_group import (
import_functional_groups,
)

file = shared_datadir / "example_functional_group_import.csv"
fg_list = import_functional_groups(file, constants_instance)

return fg_list[16]


@pytest.fixture
def fungivore_cohort_instance(
fungivore_functional_group_instance,
animal_data_for_cohorts_instance,
constants_instance,
):
"""Fixture for an animal cohort used in tests."""
from virtual_ecosystem.models.animal.animal_cohorts import AnimalCohort

return AnimalCohort(
fungivore_functional_group_instance,
10000.0,
1,
10,
1, # centroid
animal_data_for_cohorts_instance.grid, # grid
constants_instance,
)


@pytest.fixture
def predator_functional_group_instance(shared_datadir, constants_instance):
"""Fixture for an animal functional group used in tests."""
Expand Down Expand Up @@ -1108,3 +1141,36 @@ def herbivory_waste_pool_instance():
)

return herbivory_waste


@pytest.fixture
def mushroom_instance(litter_soil_data_instance):
"""Fixture for a single FungalFruitPool object."""
from virtual_ecosystem.models.animal.decay import (
FungalFruitPool,
) # Adjust as needed

return FungalFruitPool(
cell_id=0,
data=litter_soil_data_instance,
cell_area=100.0, # m²
c_n_ratio=25.0,
c_p_ratio=100.0,
)


@pytest.fixture
def mushroom_list_instance(litter_soil_data_instance):
"""Fixture for multiple FungalFruitPool objects across grid cells."""
from virtual_ecosystem.models.animal.decay import FungalFruitPool

return [
FungalFruitPool(
cell_id=cell_id,
data=litter_soil_data_instance,
cell_area=100.0,
c_n_ratio=25.0,
c_p_ratio=100.0,
)
for cell_id in litter_soil_data_instance.grid.cell_id
]
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ earthworm,invertebrate,detritus,ectothermic,terrestrial,iteroparous,direct,adult
dung_beetle,invertebrate,waste,ectothermic,terrestrial,iteroparous,direct,adult,dung_beetle,uricotelic,none,soil_ground,0.0003,0.003, 0.005
scavenging_mammal,mammal,carcasses,endothermic,terrestrial,iteroparous,direct,adult,scavenging_mammal,ureotelic,none,ground,2.0,20.0, 0.005
detritivorous_insect,invertebrate,detritus,ectothermic,terrestrial,iteroparous,direct,adult,detritivorous_insect,uricotelic,none,soil_ground,0.0004,0.004, 0.005
fungivorous_mammal,mammal,fungus,endothermic,terrestrial,iteroparous,direct,adult,fungivorous_mammal,ureotelic,none,soil_ground,1.0,10.0, 0.005
38 changes: 29 additions & 9 deletions tests/models/animals/test_animal_cohorts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1864,14 +1864,15 @@ def test_delta_mass_excrement_scavenging_calls_forage_resource_list(
assert result == {"carbon": 4.0, "nitrogen": 1.0, "phosphorus": 0.5}

@pytest.mark.parametrize(
"cohort_instance, diet_type, plant_list, animal_list, expected_nutrient_gain,"
"delta_mass_mock",
"cohort_instance, diet_type, plant_list, animal_list, mushroom_list,"
" expected_nutrient_gain, delta_mass_mock",
[
(
"herbivore_cohort_instance",
"HERBIVORE",
"plant_list_instance",
[],
[],
{"carbon": 60.0, "nitrogen": 30.0, "phosphorus": 10.0},
"delta_mass_herbivory",
),
Expand All @@ -1880,10 +1881,21 @@ def test_delta_mass_excrement_scavenging_calls_forage_resource_list(
"CARNIVORE",
[],
"animal_list_instance",
[],
{"carbon": 120.0, "nitrogen": 60.0, "phosphorus": 20.0},
"delta_mass_predation",
),
(
"fungivore_cohort_instance",
"FUNGUS",
[],
[],
"mushroom_list_instance",
{"carbon": 25.0, "nitrogen": 5.0, "phosphorus": 2.5},
"delta_mass_fruiting_fungivory",
),
],
ids=["herbivore", "carnivore", "fungivore"],
)
def test_forage_cohort(
self,
Expand All @@ -1893,10 +1905,12 @@ def test_forage_cohort(
diet_type,
plant_list,
animal_list,
mushroom_list,
expected_nutrient_gain,
delta_mass_mock,
plant_list_instance,
animal_list_instance,
mushroom_list_instance,
excrement_pool_instance,
carcass_pools_by_cell_instance,
herbivory_waste_pool_instance,
Expand All @@ -1913,6 +1927,8 @@ def test_forage_cohort(
plant_list = request.getfixturevalue(plant_list)
if isinstance(animal_list, str):
animal_list = request.getfixturevalue(animal_list)
if isinstance(mushroom_list, str):
mushroom_list = request.getfixturevalue(mushroom_list)

# Construct herbivory waste pools if herbivore
herbivory_waste_pools = {
Expand All @@ -1924,7 +1940,6 @@ def test_forage_cohort(
mock_delta_mass = mocker.patch.object(
cohort, delta_mass_mock, return_value=expected_nutrient_gain
)
mock_eat = mocker.patch.object(cohort, "eat")

# Dummy values for untested inputs
empty_list = []
Expand All @@ -1933,8 +1948,9 @@ def test_forage_cohort(
cohort.forage_cohort(
plant_list=plant_list,
animal_list=animal_list,
mushroom_list=mushroom_list,
litter_pools=empty_list,
excrement_pools=excrement_pool_instance,
excrement_pools=[excrement_pool_instance],
carcass_pool_map=carcass_pools_by_cell_instance,
scavenge_carcass_pools=empty_list,
scavenge_excrement_pools=empty_list,
Expand All @@ -1953,15 +1969,17 @@ def test_forage_cohort(
assert kwargs["herbivory_waste_pools"] == herbivory_waste_pools
assert isinstance(kwargs["adjusted_dt"], int | float)

else:
elif diet_type == "CARNIVORE":
assert kwargs["animal_list"] == animal_list_instance
assert kwargs["carcass_pools"] == carcass_pools_by_cell_instance
assert isinstance(kwargs["adjusted_dt"], int | float)

# Validate assimilation call
mock_eat.assert_called_once_with(
expected_nutrient_gain, excrement_pool_instance
)
elif diet_type == "FUNGUS":
assert kwargs["mushroom_list"] == mushroom_list_instance
assert isinstance(kwargs["adjusted_dt"], int | float)

else:
assert False, f"Unhandled diet_type: {diet_type}"

def test_forage_cohort_skips_when_no_individuals(
self, mocker, herbivore_cohort_instance
Expand All @@ -1981,6 +1999,7 @@ def test_forage_cohort_skips_when_no_individuals(
cohort.forage_cohort(
plant_list=[],
animal_list=[],
mushroom_list=[],
litter_pools=[],
excrement_pools=[],
carcass_pool_map={},
Expand Down Expand Up @@ -2011,6 +2030,7 @@ def test_forage_cohort_skips_when_no_mass(self, mocker, herbivore_cohort_instanc
cohort.forage_cohort(
plant_list=[],
animal_list=[],
mushroom_list=[],
litter_pools=[],
excrement_pools=[],
carcass_pool_map={},
Expand Down
22 changes: 22 additions & 0 deletions tests/models/animals/test_animal_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,28 @@ def test_forage_community(
"predator": predator_cohort_instance,
}

# Show where AnimalModel comes from (guards against stray imports)
import inspect

from virtual_ecosystem.models.animal.animal_model import AnimalModel

# Comment: make failures descriptive and short to read in pytest output.
assert hasattr(animal_model_instance, "plant_resources"), (
"plant_resources missing. "
f"_setup defined at: {inspect.getsourcefile(AnimalModel._setup)}:"
f"{inspect.getsourcelines(AnimalModel._setup)[1]} | "
f"attrs={sorted(vars(animal_model_instance))}"
)

# Optional: verify other _setup outputs exist; helps pinpoint where it failed.
for name in (
"excrement_pools",
"carcass_pools",
"leaf_waste_pools",
"litter_pools",
):
assert hasattr(animal_model_instance, name), f"Missing {name}"

# Run the forage_community method
animal_model_instance.forage_community(dt=30)

Expand Down
32 changes: 30 additions & 2 deletions tests/models/animals/test_scaling_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def test_herbivore_prey_group_selection(functional_group_list_instance):
expected = {
"plants": (0.0, 0.0),
"litter": (0.0, 0.0),
"fungal_fruiting_bodies": (0.0, 0.0),
}
assert result == expected

Expand Down Expand Up @@ -191,12 +192,29 @@ def test_carnivore_prey_group_selection(functional_group_list_instance):
"detritivorous_insect": (0.0001, 1000.0),
"dung_beetle": (0.0001, 1000.0),
"scavenging_mammal": (0.0001, 1000.0),
"fungivorous_mammal": (0.0001, 1000.0),
"carcasses": (0.0, 0.0),
"excrement": (0.0, 0.0),
}
assert result == expected_output


def test_fungivore_prey_group_selection(functional_group_list_instance):
"""Test for fungivore diet type selection."""
from virtual_ecosystem.models.animal.scaling_functions import (
DietType,
prey_group_selection,
)

result = prey_group_selection(
DietType.FUNGUS, 10.0, (0.1, 1000.0), functional_group_list_instance
)
expected = {
"fungal_fruiting_bodies": (0.0, 0.0),
}
assert result == expected


@pytest.mark.parametrize(
"diet_flag, expected",
[
Expand All @@ -211,12 +229,22 @@ def test_carnivore_prey_group_selection(functional_group_list_instance):
# Herbivory + scavenging
(
DietType.HERBIVORE | DietType.CARCASSES,
{"plants": (0.0, 0.0), "litter": (0.0, 0.0), "carcasses": (0.0, 0.0)},
{
"plants": (0.0, 0.0),
"litter": (0.0, 0.0),
"carcasses": (0.0, 0.0),
"fungal_fruiting_bodies": (0.0, 0.0),
},
),
# Herbivory + waste
(
DietType.HERBIVORE | DietType.WASTE,
{"plants": (0.0, 0.0), "litter": (0.0, 0.0), "excrement": (0.0, 0.0)},
{
"plants": (0.0, 0.0),
"litter": (0.0, 0.0),
"excrement": (0.0, 0.0),
"fungal_fruiting_bodies": (0.0, 0.0),
},
),
# Detritivory only
(
Expand Down
Loading
Loading