|
| 1 | +import pytest |
| 2 | +from unittest.mock import patch, MagicMock |
| 3 | +from django.core.exceptions import ValidationError |
| 4 | + |
| 5 | +from country_workspace.state import state |
| 6 | +from country_workspace.contrib.hope.beneficiary_reference import ( |
| 7 | + get_household_id_from_request, |
| 8 | + BeneficiarySelect2Widget, |
| 9 | + BeneficiaryReferenceModelChoice, |
| 10 | +) |
| 11 | + |
| 12 | + |
| 13 | +@pytest.fixture |
| 14 | +def office(): |
| 15 | + from testutils.factories import OfficeFactory |
| 16 | + |
| 17 | + co = OfficeFactory() |
| 18 | + state.tenant = co |
| 19 | + return co |
| 20 | + |
| 21 | + |
| 22 | +@pytest.fixture |
| 23 | +def program(office): |
| 24 | + from testutils.factories import CountryProgramFactory |
| 25 | + |
| 26 | + return CountryProgramFactory(country_office=office) |
| 27 | + |
| 28 | + |
| 29 | +@pytest.fixture |
| 30 | +def household(program): |
| 31 | + from testutils.factories import CountryHouseholdFactory |
| 32 | + |
| 33 | + return CountryHouseholdFactory(batch__program=program) |
| 34 | + |
| 35 | + |
| 36 | +@pytest.fixture |
| 37 | +def individual(household): |
| 38 | + return household.members.first() |
| 39 | + |
| 40 | + |
| 41 | +@pytest.fixture |
| 42 | +def multiple_households(program): |
| 43 | + from testutils.factories import CountryHouseholdFactory |
| 44 | + |
| 45 | + return [CountryHouseholdFactory(batch__program=program) for _ in range(3)] |
| 46 | + |
| 47 | + |
| 48 | +@pytest.fixture |
| 49 | +def all_individuals(multiple_households): |
| 50 | + individuals = [] |
| 51 | + for hh in multiple_households: |
| 52 | + individuals.extend(hh.members.all()) |
| 53 | + return individuals |
| 54 | + |
| 55 | + |
| 56 | +@pytest.mark.parametrize( |
| 57 | + ("request_data", "expected"), |
| 58 | + [ |
| 59 | + (None, None), |
| 60 | + (MagicMock(kwargs={"object_id": "456"}), 456), |
| 61 | + (MagicMock(kwargs={}), None), |
| 62 | + ], |
| 63 | +) |
| 64 | +def test_get_household_id_from_request(request_data, expected): |
| 65 | + with ( |
| 66 | + patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state, |
| 67 | + patch("country_workspace.contrib.hope.beneficiary_reference.resolve") as mock_resolve, |
| 68 | + ): |
| 69 | + if request_data is None: |
| 70 | + mock_state.request = None |
| 71 | + else: |
| 72 | + mock_resolve.return_value = request_data |
| 73 | + |
| 74 | + assert get_household_id_from_request() == expected |
| 75 | + |
| 76 | + |
| 77 | +@pytest.mark.parametrize( |
| 78 | + ("program_id", "household_id"), |
| 79 | + [ |
| 80 | + (None, None), |
| 81 | + (123, None), |
| 82 | + (123, 456), |
| 83 | + ], |
| 84 | +) |
| 85 | +def test_beneficiary_widget_init(program_id, household_id): |
| 86 | + widget = BeneficiarySelect2Widget(program_id=program_id, household_id=household_id) |
| 87 | + assert widget.program_id == program_id |
| 88 | + assert widget.household_id == household_id |
| 89 | + |
| 90 | + |
| 91 | +@pytest.mark.django_db |
| 92 | +@pytest.mark.parametrize("program_id", [99999, None], ids=["non_existing_program", "no_program"]) |
| 93 | +def test_widget_get_queryset_returns_empty_for_invalid_or_missing_program(program_id): |
| 94 | + widget = BeneficiarySelect2Widget(program_id=program_id) |
| 95 | + queryset = widget.get_queryset() |
| 96 | + assert queryset.count() == 0 |
| 97 | + |
| 98 | + |
| 99 | +@pytest.mark.django_db |
| 100 | +def test_widget_get_queryset_with_household_filter(program, household, individual): |
| 101 | + widget = BeneficiarySelect2Widget(program_id=program.id, household_id=household.id) |
| 102 | + assert individual in widget.get_queryset() |
| 103 | + |
| 104 | + |
| 105 | +@pytest.mark.django_db |
| 106 | +@pytest.mark.parametrize("filter_by_household", [True, False]) |
| 107 | +def test_field_init(program, household, individual, multiple_households, all_individuals, filter_by_household): |
| 108 | + with ( |
| 109 | + patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state, |
| 110 | + patch("country_workspace.contrib.hope.beneficiary_reference.get_household_id_from_request") as mock_get, |
| 111 | + ): |
| 112 | + mock_state.program = program |
| 113 | + mock_get.return_value = household.id if filter_by_household else None |
| 114 | + |
| 115 | + field = BeneficiaryReferenceModelChoice(filter_by_household=filter_by_household) |
| 116 | + |
| 117 | + if filter_by_household: |
| 118 | + assert individual in field.queryset |
| 119 | + assert all(ind.household == household for ind in field.queryset) |
| 120 | + else: |
| 121 | + for ind in all_individuals: |
| 122 | + assert ind in field.queryset |
| 123 | + |
| 124 | + |
| 125 | +@pytest.mark.django_db |
| 126 | +@pytest.mark.parametrize( |
| 127 | + ("value", "expected"), |
| 128 | + [ |
| 129 | + (None, None), |
| 130 | + ("", None), |
| 131 | + ([], None), |
| 132 | + ], |
| 133 | +) |
| 134 | +def test_to_python_empty_values(program, value, expected): |
| 135 | + with patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state: |
| 136 | + mock_state.program = program |
| 137 | + field = BeneficiaryReferenceModelChoice() |
| 138 | + assert field.to_python(value) == expected |
| 139 | + |
| 140 | + |
| 141 | +@pytest.mark.django_db |
| 142 | +def test_to_python_valid_id(program, all_individuals): |
| 143 | + with patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state: |
| 144 | + mock_state.program = program |
| 145 | + field = BeneficiaryReferenceModelChoice() |
| 146 | + individual = all_individuals[0] |
| 147 | + assert field.to_python(str(individual.pk)) == individual.name |
| 148 | + |
| 149 | + |
| 150 | +@pytest.mark.django_db |
| 151 | +@pytest.mark.parametrize( |
| 152 | + ("value", "should_raise"), |
| 153 | + [ |
| 154 | + ("99999", True), # Invalid ID |
| 155 | + (99999, True), # Invalid ID as int |
| 156 | + ("Non Existing Name", True), # Non-existing name |
| 157 | + (["invalid", "list"], True), # Invalid type |
| 158 | + ], |
| 159 | +) |
| 160 | +def test_to_python_validation_errors(program, value, should_raise): |
| 161 | + with patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state: |
| 162 | + mock_state.program = program |
| 163 | + field = BeneficiaryReferenceModelChoice() |
| 164 | + |
| 165 | + if should_raise: |
| 166 | + with pytest.raises(ValidationError): |
| 167 | + field.to_python(value) |
| 168 | + |
| 169 | + |
| 170 | +@pytest.mark.django_db |
| 171 | +def test_to_python_existing_name(program, all_individuals): |
| 172 | + with patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state: |
| 173 | + mock_state.program = program |
| 174 | + field = BeneficiaryReferenceModelChoice() |
| 175 | + individual = all_individuals[0] |
| 176 | + |
| 177 | + # Test with existing name - should return the same name |
| 178 | + result = field.to_python(individual.name) |
| 179 | + assert result == individual.name |
| 180 | + |
| 181 | + |
| 182 | +@pytest.mark.django_db |
| 183 | +@pytest.mark.parametrize("input_type", ["pk_int", "name", "object", "non_existing_name", "empty_string"]) |
| 184 | +def test_prepare_value(program, all_individuals, input_type): |
| 185 | + with patch("country_workspace.contrib.hope.beneficiary_reference.state") as mock_state: |
| 186 | + mock_state.program = program |
| 187 | + field = BeneficiaryReferenceModelChoice() |
| 188 | + individual = all_individuals[0] |
| 189 | + |
| 190 | + match input_type: |
| 191 | + case "pk_int": |
| 192 | + result = field.prepare_value(individual.pk) |
| 193 | + assert result == individual.pk |
| 194 | + case "name": |
| 195 | + result = field.prepare_value(individual.name) |
| 196 | + assert result == individual.pk |
| 197 | + case "object": |
| 198 | + result = field.prepare_value(individual) |
| 199 | + assert result == individual.pk |
| 200 | + case "non_existing_name": |
| 201 | + result = field.prepare_value("Non Existing Name") |
| 202 | + assert result is None |
| 203 | + case "empty_string": |
| 204 | + result = field.prepare_value("") |
| 205 | + assert result == "" |
0 commit comments