Skip to content

Commit 3920732

Browse files
committed
test(links): add regression tests for non-default person entity key
Add tests verifying ImplicitOne2ManyLink and _resolve_links work when the person entity has a key other than 'person' (e.g. 'individu' in openfisca-france): - test_implicit_one2many_with_non_default_person_key (unit) - test_resolve_links_with_individu_key (integration) - test_implicit_link_target_uses_actual_person_key (integration)
1 parent 73b739b commit 3920732

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

openfisca_core/links/tests/test_implicit.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,50 @@ def test_implicit_one2many(sim):
7474

7575
counts = link.count("2024")
7676
assert numpy.array_equal(counts, [2, 1, 1])
77+
78+
79+
def test_implicit_one2many_with_non_default_person_key():
80+
"""Regression test: entity key != 'person' must not crash.
81+
82+
openfisca-france uses 'individu' as the person entity key.
83+
Before the fix, ImplicitOne2ManyLink hardcoded target_entity_key='person',
84+
causing a KeyError during link resolution.
85+
"""
86+
individu = entities.SingleEntity("individu", "individus", "Un individu", "")
87+
menage = entities.GroupEntity(
88+
"menage",
89+
"menages",
90+
"Un ménage",
91+
"",
92+
roles=[{"key": "personne_de_reference"}],
93+
)
94+
95+
tbs = taxbenefitsystems.TaxBenefitSystem([individu, menage])
96+
97+
class salaire(variables.Variable):
98+
value_type = float
99+
entity = individu
100+
definition_period = periods.DateUnit.YEAR
101+
102+
tbs.add_variable(salaire)
103+
104+
sim = SimulationBuilder().build_from_dict(
105+
tbs,
106+
{
107+
"individus": {
108+
"i0": {"salaire": {"2024": 1000.0}},
109+
"i1": {"salaire": {"2024": 500.0}},
110+
},
111+
"menages": {
112+
"m0": {"personne_de_reference": ["i0", "i1"]},
113+
},
114+
},
115+
)
116+
117+
# The implicit O2M link should resolve with target_entity_key='individu'
118+
link = ImplicitOne2ManyLink("individus", "menage", "individu")
119+
link.attach(sim.populations["menage"])
120+
link.resolve(sim.populations) # Would raise KeyError before the fix
121+
122+
salaires = link.sum("salaire", "2024")
123+
assert numpy.array_equal(salaires, [1500.0])

openfisca_core/links/tests/test_integration.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,55 @@ def test_no_links_no_problem(self):
190190

191191
# Simulation should work fine
192192
assert sim.persons.count == 2
193+
194+
195+
# -- Regression test: non-default person entity key -----------------------
196+
197+
198+
class TestNonDefaultPersonKey:
199+
"""Verify that _resolve_links works when person entity key != 'person'.
200+
201+
This is a regression test for the France API crash where the person
202+
entity is named 'individu' instead of 'person'.
203+
"""
204+
205+
def test_resolve_links_with_individu_key(self):
206+
"""Simulation.__init__ must not crash with entity key 'individu'."""
207+
individu = entities.SingleEntity(
208+
"individu", "individus", "Un individu", ""
209+
)
210+
menage = entities.GroupEntity(
211+
"menage",
212+
"menages",
213+
"Un ménage",
214+
"",
215+
roles=[{"key": "personne_de_reference"}],
216+
)
217+
tbs = taxbenefitsystems.TaxBenefitSystem([individu, menage])
218+
# This line triggered the KeyError before the fix
219+
sim = SimulationBuilder().build_default_simulation(tbs, count=3)
220+
221+
assert sim.persons.count == 3
222+
# Implicit links should be auto-generated with correct keys
223+
assert "menage" in sim.persons.links # individu → menage (M2O)
224+
assert "individus" in sim.populations["menage"].links # menage → individus (O2M)
225+
226+
def test_implicit_link_target_uses_actual_person_key(self):
227+
"""The O2M link target must be 'individu', not 'person'."""
228+
individu = entities.SingleEntity(
229+
"individu", "individus", "Un individu", ""
230+
)
231+
foyer_fiscal = entities.GroupEntity(
232+
"foyer_fiscal",
233+
"foyers_fiscaux",
234+
"Un foyer fiscal",
235+
"",
236+
roles=[{"key": "declarant"}],
237+
)
238+
tbs = taxbenefitsystems.TaxBenefitSystem([individu, foyer_fiscal])
239+
sim = SimulationBuilder().build_default_simulation(tbs, count=2)
240+
241+
o2m_link = sim.populations["foyer_fiscal"].links["individus"]
242+
assert o2m_link.target_entity_key == "individu"
243+
assert o2m_link.is_resolved
244+
assert o2m_link._target_population is sim.persons

0 commit comments

Comments
 (0)