Skip to content

Commit 46b083f

Browse files
authored
Merge pull request #464 from ansforge/feat/converter/nomenclatures/add-cisu-version-conversion
Feat/converter/nomenclatures/add cisu version conversion
2 parents ddda8b0 + 6fb9f68 commit 46b083f

7 files changed

Lines changed: 363 additions & 39 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class CISUConstants:
22
TO_CISU = "to_CISU"
33
FROM_CISU = "from_CISU"
4-
CISU_EXPECTED_MODEL_VERSION = "v3"
4+
CISU_EXPECTED_MODEL_VERSION = "vactive"
55
HEALTH_EXPECTED_VERSION_FOR_CISU_CONVERSION = "v3"

converter/converter/cisu_version_converters/base_cisu_version_converter.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ def get_message_type(cls) -> str:
2424
"Subclasses must implement this method to return the message type in RS specifications."
2525
)
2626

27+
@classmethod
28+
def copy_input_content(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
29+
return cls._copy_input_content(edxl_json, cls.get_message_type())
30+
31+
@classmethod
32+
def copy_input_use_case_content(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
33+
return cls._copy_input_use_case_content(edxl_json, cls.get_message_type())
34+
35+
@classmethod
36+
def format_output_json(
37+
cls,
38+
output_json: Dict[str, Any],
39+
output_use_case_json: Dict[str, Any],
40+
) -> Dict[str, Any]:
41+
return cls._format_output_json(
42+
output_json, output_use_case_json, cls.get_message_type()
43+
)
44+
2745
@classmethod
2846
def convert(
2947
cls, source_version: str, target_version: str, edxl_json: Dict[str, Any]
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from typing import Any, Dict
2+
3+
from converter.cisu_transcoders.create_case.create_case_cisu_constants import (
4+
CreateCaseCISUConstants,
5+
)
6+
from converter.cisu_version_converters.base_cisu_version_converter import (
7+
BaseCISUVersionConverter,
8+
)
9+
from converter.nomenclatures.utils import (
10+
apply_nomenclature_mapping,
11+
apply_nomenclature_mapping_to_list,
12+
)
13+
from converter.nomenclatures.from_v1_9_to_v2_3.whats_happen import (
14+
V1_9_TO_V2_3_WHATS_HAPPEN_MAP,
15+
)
16+
from converter.nomenclatures.from_v1_9_to_v2_3.health_motive import (
17+
V1_9_TO_V2_3_HEALTH_MOTIVE_MAP,
18+
)
19+
from converter.nomenclatures.from_v1_9_to_v2_3.risk_threat import (
20+
V1_9_TO_V2_3_RISK_THREAT_MAP,
21+
)
22+
from converter.nomenclatures.from_v1_9_to_v2_3.location_kind import (
23+
V1_9_TO_V2_3_LOCATION_KIND_MAP,
24+
)
25+
from converter.nomenclatures.from_v2_3_to_v1_9.whats_happen import (
26+
V2_3_TO_V1_9_WHATS_HAPPEN_MAP,
27+
)
28+
from converter.nomenclatures.from_v2_3_to_v1_9.health_motive import (
29+
V2_3_TO_V1_9_HEALTH_MOTIVE_MAP,
30+
)
31+
from converter.nomenclatures.from_v2_3_to_v1_9.risk_threat import (
32+
V2_3_TO_V1_9_RISK_THREAT_MAP,
33+
)
34+
from converter.nomenclatures.from_v2_3_to_v1_9.location_kind import (
35+
V2_3_TO_V1_9_LOCATION_KIND_MAP,
36+
)
37+
38+
39+
class CreateCaseVersionConverter(BaseCISUVersionConverter):
40+
@classmethod
41+
def get_message_type(cls) -> str:
42+
return "createCase"
43+
44+
@classmethod
45+
def convert_v3_to_vactive(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
46+
output_json = cls.copy_input_content(edxl_json)
47+
output_use_case_json = cls.copy_input_use_case_content(edxl_json)
48+
49+
apply_nomenclature_mapping(
50+
output_use_case_json,
51+
CreateCaseCISUConstants.QUALIFICATION_WHATS_HAPPEN_PATH,
52+
V2_3_TO_V1_9_WHATS_HAPPEN_MAP,
53+
)
54+
apply_nomenclature_mapping(
55+
output_use_case_json,
56+
CreateCaseCISUConstants.QUALIFICATION_HEALTH_MOTIVE_PATH,
57+
V2_3_TO_V1_9_HEALTH_MOTIVE_MAP,
58+
)
59+
apply_nomenclature_mapping_to_list(
60+
output_use_case_json,
61+
CreateCaseCISUConstants.QUALIFICATION_RISK_THREAT_PATH,
62+
V2_3_TO_V1_9_RISK_THREAT_MAP,
63+
)
64+
apply_nomenclature_mapping(
65+
output_use_case_json,
66+
CreateCaseCISUConstants.QUALIFICATION_LOCATION_KIND_PATH,
67+
V2_3_TO_V1_9_LOCATION_KIND_MAP,
68+
)
69+
70+
return cls.format_output_json(output_json, output_use_case_json)
71+
72+
@classmethod
73+
def convert_vactive_to_v3(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
74+
output_json = cls.copy_input_content(edxl_json)
75+
output_use_case_json = cls.copy_input_use_case_content(edxl_json)
76+
77+
apply_nomenclature_mapping(
78+
output_use_case_json,
79+
CreateCaseCISUConstants.QUALIFICATION_WHATS_HAPPEN_PATH,
80+
V1_9_TO_V2_3_WHATS_HAPPEN_MAP,
81+
)
82+
apply_nomenclature_mapping(
83+
output_use_case_json,
84+
CreateCaseCISUConstants.QUALIFICATION_HEALTH_MOTIVE_PATH,
85+
V1_9_TO_V2_3_HEALTH_MOTIVE_MAP,
86+
)
87+
apply_nomenclature_mapping_to_list(
88+
output_use_case_json,
89+
CreateCaseCISUConstants.QUALIFICATION_RISK_THREAT_PATH,
90+
V1_9_TO_V2_3_RISK_THREAT_MAP,
91+
)
92+
apply_nomenclature_mapping(
93+
output_use_case_json,
94+
CreateCaseCISUConstants.QUALIFICATION_LOCATION_KIND_PATH,
95+
V1_9_TO_V2_3_LOCATION_KIND_MAP,
96+
)
97+
98+
return cls.format_output_json(output_json, output_use_case_json)

converter/converter/cisu_version_converters/create_case/rc_eda_version_converter.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

converter/converter/conversion_strategy/cisu_version_conversion_strategy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from converter.cisu_version_converters.create_case.rc_eda_version_converter import (
2+
from converter.cisu_version_converters.create_case.create_case_version_converter import (
33
CreateCaseVersionConverter,
44
)
55
from converter.cisu_version_converters.resources_info_cisu.resources_info_cisu_version_converter import (
Lines changed: 161 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,168 @@
1-
import unittest
1+
"""Unit tests for CreateCaseVersionConverter.convert_v3_to_vactive /
2+
convert_vactive_to_v3, calling the converter directly (no Flask/HTTP).
23
3-
from converter.cisu_version_converters.create_case.rc_eda_version_converter import (
4+
convert_v3_to_vactive mirrors from_rs_to_cisu's mapping direction
5+
(2.3 -> 1.9 nomenclature); convert_vactive_to_v3 mirrors from_cisu_to_rs's
6+
(1.9 -> 2.3 nomenclature).
7+
8+
Test cases are generated from the real nomenclature maps rather than
9+
hardcoded codes, so they stay correct if the maps are regenerated. Each map
10+
is only exercised on the scenarios it actually contains: as of this writing,
11+
7 of the 8 (field, direction) maps have no entry mapped to None, and
12+
riskThreat's v1.9->2.3 map (used by convert_vactive_to_v3) has no entry
13+
mapped to a value (its single entry maps to None) -- those scenarios are
14+
legitimately absent, not skipped by omission.
15+
"""
16+
17+
import pytest
18+
19+
from converter.cisu_version_converters.create_case.create_case_version_converter import (
420
CreateCaseVersionConverter,
521
)
22+
from converter.nomenclatures.from_v1_9_to_v2_3.health_motive import (
23+
V1_9_TO_V2_3_HEALTH_MOTIVE_MAP,
24+
)
25+
from converter.nomenclatures.from_v1_9_to_v2_3.location_kind import (
26+
V1_9_TO_V2_3_LOCATION_KIND_MAP,
27+
)
28+
from converter.nomenclatures.from_v1_9_to_v2_3.risk_threat import (
29+
V1_9_TO_V2_3_RISK_THREAT_MAP,
30+
)
31+
from converter.nomenclatures.from_v1_9_to_v2_3.whats_happen import (
32+
V1_9_TO_V2_3_WHATS_HAPPEN_MAP,
33+
)
34+
from converter.nomenclatures.from_v2_3_to_v1_9.health_motive import (
35+
V2_3_TO_V1_9_HEALTH_MOTIVE_MAP,
36+
)
37+
from converter.nomenclatures.from_v2_3_to_v1_9.location_kind import (
38+
V2_3_TO_V1_9_LOCATION_KIND_MAP,
39+
)
40+
from converter.nomenclatures.from_v2_3_to_v1_9.risk_threat import (
41+
V2_3_TO_V1_9_RISK_THREAT_MAP,
42+
)
43+
from converter.nomenclatures.from_v2_3_to_v1_9.whats_happen import (
44+
V2_3_TO_V1_9_WHATS_HAPPEN_MAP,
45+
)
46+
from tests.cisu.helpers import get_edxl_message
647
from tests.constants import TestConstants
748
from tests.test_helpers import TestHelper
849

50+
UNCHANGED = "sentinel: field left as injected"
51+
REMOVED = "sentinel: field removed from qualification"
52+
UNMAPPED_CODE = "UNMAPPED-TEST-CODE"
53+
54+
BASE_MESSAGE_PATH = "tests/fixtures/RC-EDA/RC-EDA_required_fields.json"
55+
56+
# (qualification field, is a list field, map used by convert_v3_to_vactive, map used by convert_vactive_to_v3)
57+
FIELD_SPECS = [
58+
(
59+
"whatsHappen",
60+
False,
61+
V2_3_TO_V1_9_WHATS_HAPPEN_MAP,
62+
V1_9_TO_V2_3_WHATS_HAPPEN_MAP,
63+
),
64+
(
65+
"healthMotive",
66+
False,
67+
V2_3_TO_V1_9_HEALTH_MOTIVE_MAP,
68+
V1_9_TO_V2_3_HEALTH_MOTIVE_MAP,
69+
),
70+
(
71+
"riskThreat",
72+
True,
73+
V2_3_TO_V1_9_RISK_THREAT_MAP,
74+
V1_9_TO_V2_3_RISK_THREAT_MAP,
75+
),
76+
(
77+
"locationKind",
78+
False,
79+
V2_3_TO_V1_9_LOCATION_KIND_MAP,
80+
V1_9_TO_V2_3_LOCATION_KIND_MAP,
81+
),
82+
]
83+
84+
85+
def _first_entry(mapping, *, mapped_to_none):
86+
return next(
87+
(
88+
(code, value)
89+
for code, value in mapping.items()
90+
if (value is None) == mapped_to_none
91+
),
92+
None,
93+
)
94+
95+
96+
def _build_cases():
97+
cases = []
98+
for field, is_list, v3_to_vactive_map, vactive_to_v3_map in FIELD_SPECS:
99+
for method_name, mapping in [
100+
("convert_v3_to_vactive", v3_to_vactive_map),
101+
("convert_vactive_to_v3", vactive_to_v3_map),
102+
]:
103+
cases.append(
104+
pytest.param(
105+
field,
106+
is_list,
107+
method_name,
108+
UNMAPPED_CODE,
109+
UNCHANGED,
110+
id=f"{field}-{method_name}-unmapped",
111+
)
112+
)
113+
114+
mapped_value_entry = _first_entry(mapping, mapped_to_none=False)
115+
if mapped_value_entry is not None:
116+
code, expected_value = mapped_value_entry
117+
cases.append(
118+
pytest.param(
119+
field,
120+
is_list,
121+
method_name,
122+
code,
123+
expected_value,
124+
id=f"{field}-{method_name}-mapped_to_value",
125+
)
126+
)
127+
128+
mapped_none_entry = _first_entry(mapping, mapped_to_none=True)
129+
if mapped_none_entry is not None:
130+
code, _ = mapped_none_entry
131+
cases.append(
132+
pytest.param(
133+
field,
134+
is_list,
135+
method_name,
136+
code,
137+
REMOVED,
138+
id=f"{field}-{method_name}-mapped_to_none",
139+
)
140+
)
141+
return cases
142+
143+
144+
@pytest.mark.parametrize(
145+
"field, is_list, method_name, injected_code, expected",
146+
_build_cases(),
147+
)
148+
def test_nomenclature_mapping(field, is_list, method_name, injected_code, expected):
149+
message = TestHelper.create_edxl_json_from_sample(
150+
TestConstants.EDXL_FIRE_TO_HEALTH_ENVELOPE_PATH, BASE_MESSAGE_PATH
151+
)
152+
injected_value = {"code": injected_code, "label": "Libellé de test"}
153+
qualification = get_edxl_message(message)["createCase"]["qualification"]
154+
qualification[field] = [injected_value] if is_list else injected_value
155+
156+
convert = getattr(CreateCaseVersionConverter, method_name)
157+
result = convert(message)
158+
159+
result_qualification = get_edxl_message(result)["createCase"]["qualification"]
9160

10-
class TestCreateCaseVersionConverter(unittest.TestCase):
11-
def setUp(self):
12-
self.edxl_envelope_health_to_fire_path = (
13-
TestConstants.EDXL_HEALTH_TO_FIRE_ENVELOPE_PATH
14-
)
15-
self.edxl_envelope_fire_to_health_path = (
16-
TestConstants.EDXL_FIRE_TO_HEALTH_ENVELOPE_PATH
17-
)
18-
self.fixtures_folder_path = "tests/fixtures/"
19-
self.converter = CreateCaseVersionConverter
20-
21-
def test_v3_to_vactive(self):
22-
message = TestHelper.create_edxl_json_from_sample(
23-
self.edxl_envelope_health_to_fire_path,
24-
self.fixtures_folder_path + "RC-EDA/RC-EDA_exhaustive_fill.json",
25-
)
26-
converted_message = self.converter.convert_v3_to_vactive(message)
27-
assert converted_message == message
28-
29-
def test_vactive_to_v3(self):
30-
message = TestHelper.create_edxl_json_from_sample(
31-
self.edxl_envelope_fire_to_health_path,
32-
self.fixtures_folder_path + "RC-EDA/RC-EDA_exhaustive_fill.json",
33-
)
34-
converted_message = self.converter.convert_vactive_to_v3(message)
35-
assert converted_message == message
161+
if expected == REMOVED:
162+
assert field not in result_qualification
163+
elif expected == UNCHANGED:
164+
expected_field_value = [injected_value] if is_list else injected_value
165+
assert result_qualification[field] == expected_field_value
166+
else:
167+
expected_field_value = [expected] if is_list else expected
168+
assert result_qualification[field] == expected_field_value

0 commit comments

Comments
 (0)