diff --git a/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormDataUtils.java b/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormDataUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..17ec9b5f4098836e04019baf4a4733294fa089c0 --- /dev/null +++ b/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormDataUtils.java @@ -0,0 +1,45 @@ +package de.itvsh.kop.eingangsadapter.common.formdata; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import lombok.NonNull; + +public class FormDataUtils { + + final FormData baseFormData; + final Map<String, Object> modifieableData; + + private FormDataUtils(FormData formData) { + baseFormData = formData; + modifieableData = new HashMap<>(formData.getFormData()); + } + + public static FormDataUtils from(FormData formData) { + return new FormDataUtils(formData); + } + + public FormDataUtils remove(String key) { + modifieableData.remove(key); + return this; + } + + public FormDataUtils put(@NonNull String key, Object value) { + modifieableData.put(key, value); + return this; + } + + public FormData.FormDataBuilder builder() { + return baseFormData.toBuilder().formData(Collections.unmodifiableMap(modifieableData)); + } + + public FormData build() { + return builder().build(); + } + + @SuppressWarnings("unchecked") + public static Map<String, Object> getSubMap(FormData formData, String key) { + return (Map<String, Object>) formData.getFormData().get(key); + } +} diff --git a/common/src/test/java/de/itvsh/kop/eingangsadapter/common/formdata/FormSolutionsTestFactory.java b/common/src/test/java/de/itvsh/kop/eingangsadapter/common/formdata/FormSolutionsTestFactory.java index d372f1a0d86b24281c14dc744074d9c79d9fbbe5..f14139f0c99ecc8e93fe50487b3ac5ab9cdc3af0 100644 --- a/common/src/test/java/de/itvsh/kop/eingangsadapter/common/formdata/FormSolutionsTestFactory.java +++ b/common/src/test/java/de/itvsh/kop/eingangsadapter/common/formdata/FormSolutionsTestFactory.java @@ -45,6 +45,7 @@ public class FormSolutionsTestFactory { public static final String ZUSTAENDIGE_STELLE_VALUE = "zustaendigeStelle"; public static final String POSTFACH_ID_STELLE = "51522620-03d2-4507-b1f0-08d86920efed"; public static final String FORM_ID_VALUE = "KFAS_KOP_TEST-yCkgCdqG"; + // TODO vereinfachen und in Datei(en acken public static final String SIMPLE_JSON_DATA = "{\"assistant\": " + "{\"identifier\":\"" + IDENTIFIER_VALUE + "\",\n" + "\"panels\": [{\"identifier\":\"" + PANEL_ID + "\",\n" diff --git a/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsFileMapper.java b/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsFileMapper.java index 2f8aed6556d98f947481a6eac311288457b0aa5d..5639a6000256bcbffa897c137be62ac6323a033b 100644 --- a/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsFileMapper.java +++ b/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsFileMapper.java @@ -28,6 +28,7 @@ import java.util.UUID; import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFile; interface FormSolutionsFileMapper { + // TODO auf utils Klasse umstellen - interface abschaffen default IncomingFile mapFile(byte[] data, String contentType, String fileName) { return IncomingFile.builder() .content(data) diff --git a/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapper.java b/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapper.java index 5a38b0661eece1053f78247321e1489364769121..412ab9786cac5cb4e8ed0730cdf05db34b87564c 100644 --- a/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapper.java +++ b/formsolutions-adapter/src/main/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapper.java @@ -23,10 +23,6 @@ */ package de.itvsh.kop.eingangsadapter.formsolutions; -import static de.itvsh.kop.eingangsadapter.formsolutions.FormSolutionsAttachmentsMapper.*; -import static de.itvsh.kop.eingangsadapter.formsolutions.FormSolutionsRepresentationsMapper.*; -import static de.itvsh.kop.eingangsadapter.semantik.enginebased.AbstractFileMapper.*; - import java.util.Map; import java.util.Optional; @@ -39,9 +35,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.itvsh.kop.common.errorhandling.TechnicalException; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormDataUtils; +import de.itvsh.kop.eingangsadapter.semantik.enginebased.AbstractFileMapper; @Component class FormSolutionsRequestMapper { + static final TypeReference<Map<String, Object>> VALUE_TYPE_REF = new TypeReference<Map<String, Object>>() { + }; + @Autowired private FormSolutionsAttachmentsMapper attachmentMapper; @@ -53,31 +54,39 @@ class FormSolutionsRequestMapper { public FormData map(String json) { var formData = mapRequestJson(json); + return mapFiles(formData, json); - formData.getFormData().put(MAPPED_FILES, Map.of( - ATTACHMENTS, attachmentMapper.mapAttachments(formData.getFormData()), - REPRESENTATIONS, representationMapper.mapRepresentations(formData.getFormData(), Optional.of(json)))); - - return removeProcessedData(formData); } private FormData mapRequestJson(String json) { + + return FormData.builder() + .formData(mapFormData(json)) + .build(); + + } + + Map<String, Object> mapFormData(String json) { try { - return FormData.builder().formData(objectMapper.readValue(json, new TypeReference<Map<String, Object>>() { - })).build(); + return objectMapper.readValue(json, VALUE_TYPE_REF); } catch (JsonProcessingException e) { throw new TechnicalException("Error parsing JSON from FormSolutions-Server", e); } } -//TEST - private FormData removeProcessedData(FormData formData) { - Map<String, Object> data = formData.getFormData(); -//TODO immutable berucksichtigen - data.remove(ZIP); - data.remove(PDF); - data.remove(JSON); + FormData mapFiles(FormData formData, String json) { + return FormDataUtils.from(formData) + .put(AbstractFileMapper.FIELD_NAME_MAPPED_FILES, buildMappedFiles(formData, json)) + .remove(FormSolutionsAttachmentsMapper.ZIP) + .remove(FormSolutionsRepresentationsMapper.PDF) + .build(); - return formData.toBuilder().formData(data).build(); } + + private Map<String, Object> buildMappedFiles(FormData formData, String json) { + return Map.of( + AbstractFileMapper.ATTACHMENTS, attachmentMapper.mapAttachments(formData.getFormData()), + AbstractFileMapper.REPRESENTATIONS, representationMapper.mapRepresentations(formData.getFormData(), Optional.of(json))); + } + } \ No newline at end of file diff --git a/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapperTest.java b/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapperTest.java index 6f4fb6b1e263ba23912017ded35a96db0128d3a4..d2237c4c57206153f731020d975568033bdf39e4 100644 --- a/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapperTest.java +++ b/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/FormSolutionsRequestMapperTest.java @@ -34,11 +34,14 @@ import static org.mockito.Mockito.*; import java.util.List; import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.Spy; import com.fasterxml.jackson.core.JsonProcessingException; @@ -47,7 +50,8 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import de.itvsh.kop.common.errorhandling.TechnicalException; -import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormDataTestFactory; +import de.itvsh.kop.eingangsadapter.semantik.enginebased.AbstractFileMapper; import de.itvsh.kop.eingangsadapter.semantik.enginebased.FormSolutionsPanelMapper; class FormSolutionsRequestMapperTest { @@ -56,10 +60,10 @@ class FormSolutionsRequestMapperTest { @Spy @InjectMocks - private FormSolutionsRequestMapper mapper = new FormSolutionsRequestMapper(); + private FormSolutionsRequestMapper mapper; @Mock - private FormSolutionsAttachmentsMapper attachmentsMapper; + private FormSolutionsAttachmentsMapper attachmentMapper; @Mock private FormSolutionsRepresentationsMapper representationsMapper; @@ -70,153 +74,179 @@ class FormSolutionsRequestMapperTest { class TestJsonToMapMapping { @Test void shouldMap() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); assertThat(dataMap).isNotNull(); } - @Test - void shouldNotFillSemantikFields() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); - - assertThat(dataMap.getZustaendigeStelle()).isNull(); - assertThat(dataMap.getAntragsteller()).isNull(); - assertThat(dataMap.getHeader()).isNull(); - } - @Test void shouldContainZustaendigeStelle() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat((String) dataMap.getFormData().get(ZUSTAENDIGE_STELLE)).isEqualTo(ORGANISATIONSEINHEITEN_ID); + assertThat((String) dataMap.get(ZUSTAENDIGE_STELLE)).isEqualTo(ORGANISATIONSEINHEITEN_ID); } @Test void shouldContainAnsprechpartner() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat((String) dataMap.getFormData().get(POSTKORBHANDLE)).isEqualTo(POSTFACH_ID); + assertThat((String) dataMap.get(POSTKORBHANDLE)).isEqualTo(POSTFACH_ID); } @Test void shouldContainRequestId() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat((String) dataMap.getFormData().get(TRANSACTION_ID)).isEqualTo(FORM_ID_VALUE); + assertThat((String) dataMap.get(TRANSACTION_ID)).isEqualTo(FORM_ID_VALUE); } @Test void shouldContainAssitant() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat(dataMap.getFormData().get(ASSISTANT)).isNotNull(); + assertThat(dataMap.get(ASSISTANT)).isNotNull(); } - @SuppressWarnings("unchecked") @Test void shouldHandleJsonException() throws JsonMappingException, JsonProcessingException { - doThrow(JsonProcessingException.class).when(objectMapper).readValue(anyString(), any(TypeReference.class)); + doThrow(JsonProcessingException.class).when(objectMapper).readValue(anyString(), Mockito.<TypeReference<Map<String, Object>>>any()); - assertThatThrownBy(() -> mapper.map(SIMPLE_JSON_DATA)).isInstanceOf(TechnicalException.class); + assertThatThrownBy(() -> mapper.mapFormData(SIMPLE_JSON_DATA)).isInstanceOf(TechnicalException.class); } @Test @SuppressWarnings("unchecked") void shouldContainFormIdentifier() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat((String) ((Map<String, Object>) dataMap.getFormData().get(ASSISTANT)) + assertThat((String) ((Map<String, Object>) dataMap.get(ASSISTANT)) .get(IDENTIFIER)) .isEqualTo(IDENTIFIER_VALUE); } - @Test - void shouldRemoveZip() { - var dataMap = mapper.map(ATTACHMENTS_JSON); + @Nested + class TestPanels { + @Test + void shouldContainPanels() { + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat(dataMap.getFormData().get(FormSolutionsAttachmentsMapper.ZIP)).isNull(); - } + assertThat(getPanels(dataMap)).isNotNull(); + } - @Test - void shouldRemovePdf() { - var dataMap = mapper.map(ATTACHMENTS_JSON); + @Test + void shouldContainPanelIdentifier() { + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - assertThat(dataMap.getFormData().get(FormSolutionsRepresentationsMapper.PDF)).isNull(); - } + assertThat(getPanels(dataMap).get(0)).containsEntry(IDENTIFIER, PANEL_ID); + } - } + @Test + void shouldContainPanelComponets() { + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - @Nested - class TestPanels { - @Test - void shouldContainPanels() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + assertThat(getPanels(dataMap).get(0).get(FormSolutionsPanelMapper.COMPONENTS)).isNotNull(); + } - assertThat(getPanels(dataMap)).isNotNull(); - } + @Test + void shouldContainTextComponets() { + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - @Test - void shouldContainPanelIdentifier() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + assertThat(getComponents(dataMap).get(0)) + .containsEntry(IDENTIFIER, COMPONENT_ID) + .containsEntry(STRING_VALUE, COMPONENT_VALUE); + } - assertThat(getPanels(dataMap).get(0)).containsEntry(IDENTIFIER, PANEL_ID); - } + @Test + void shouldContainDateComponets() { + var dataMap = mapper.mapFormData(SIMPLE_JSON_DATA); - @Test - void shouldContainPanelComponets() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + assertThat(getComponents(dataMap).get(1)) + .containsEntry(IDENTIFIER, DATE_COMPONENT_ID) + .containsEntry(STRING_VALUE, DATE_COMPONENT_VALUE); + } - assertThat(getPanels(dataMap).get(0).get(FormSolutionsPanelMapper.COMPONENTS)).isNotNull(); - } + @Nested + class TestNestedPanels { + @Test + void shouldContainGroup() { + var dataMap = mapper.mapFormData(NESTED_COMPONENTS_JSON); - @Test - void shouldContainTextComponets() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + assertThat(getComponents(dataMap).get(0)).containsEntry(IDENTIFIER, OBJEKTGRUPPE_0); + } - assertThat(getComponents(dataMap).get(0)).containsEntry(IDENTIFIER, COMPONENT_ID); - assertThat(getComponents(dataMap).get(0)).containsEntry(STRING_VALUE, COMPONENT_VALUE); + @Test + void shouldContainDateField() { + var dataMap = mapper.mapFormData(NESTED_COMPONENTS_JSON); + + assertThat(getNestedComponents(dataMap).get(0)) + .containsEntry(IDENTIFIER, DATE_COMPONENT_ID) + .containsEntry(STRING_VALUE, DATE_COMPONENT_VALUE); + } + } } - @Test - void shouldContainDateComponets() { - var dataMap = mapper.map(SIMPLE_JSON_DATA); + @SuppressWarnings("unchecked") + private List<Map<String, Object>> getComponents(Map<String, Object> dataMap) { + return (List<Map<String, Object>>) getPanels(dataMap).get(0).get(COMPONENTS); + } - assertThat(getComponents(dataMap).get(1)).containsEntry(IDENTIFIER, DATE_COMPONENT_ID); - assertThat(getComponents(dataMap).get(1)).containsEntry(STRING_VALUE, DATE_COMPONENT_VALUE); + @SuppressWarnings("unchecked") + private List<Map<String, Object>> getNestedComponents(Map<String, Object> dataMap) { + return (List<Map<String, Object>>) ((List<Map<String, Object>>) getPanels(dataMap).get(0).get(COMPONENTS)).get(0).get(COMPONENTS); } + @SuppressWarnings("unchecked") + private List<Map<String, Object>> getPanels(Map<String, Object> dataMap) { + return (List<Map<String, Object>>) ((Map<String, Object>) dataMap.get(ASSISTANT)).get(PANELS); + } + } + + @Nested + class TestFileMapping { + @Nested - class TestNestedPanels { + class TestMapFiles { @Test - void shouldContainGroup() { - var dataMap = mapper.map(NESTED_COMPONENTS_JSON); + void shouldCallAttachmentMappers() { + mapper.mapFiles(FormDataTestFactory.create(), ATTACHMENTS_JSON); - assertThat(getComponents(dataMap).get(0)).containsEntry(IDENTIFIER, OBJEKTGRUPPE_0); + verify(attachmentMapper).mapAttachments(Mockito.<Map<String, Object>>any()); } + @DisplayName("result should have mapped files field") @Test - void shouldContainDateField() { - var dataMap = mapper.map(NESTED_COMPONENTS_JSON); + void shouldHaveMappedFilesField() { + var result = mapper.mapFiles(FormDataTestFactory.create(), ATTACHMENTS_JSON); - assertThat(getNestedComponents(dataMap).get(0)).containsEntry(IDENTIFIER, DATE_COMPONENT_ID); - assertThat(getNestedComponents(dataMap).get(0)).containsEntry(STRING_VALUE, DATE_COMPONENT_VALUE); + assertThat(result.getFormData()).containsKey(AbstractFileMapper.FIELD_NAME_MAPPED_FILES); } - } - } - @SuppressWarnings("unchecked") - private List<Map<String, Object>> getPanels(FormData dataMap) { - return (List<Map<String, Object>>) ((Map<String, Object>) dataMap.getFormData().get(ASSISTANT)).get(PANELS); - } + @Test + void shouldCallRepresentationMapper() { + mapper.mapFiles(FormDataTestFactory.create(), ATTACHMENTS_JSON); - @SuppressWarnings("unchecked") - private List<Map<String, Object>> getComponents(FormData dataMap) { - return (List<Map<String, Object>>) getPanels(dataMap).get(0).get(COMPONENTS); - } + verify(representationsMapper).mapRepresentations(Mockito.<Map<String, Object>>any(), eq(Optional.of(ATTACHMENTS_JSON))); + } + + @Test + void shouldRemoveZip() { + var formData = FormDataTestFactory.withFormDataMaps(Map.of(FormSolutionsAttachmentsMapper.ZIP, "test")); + + var dataMap = mapper.mapFiles(formData, ATTACHMENTS_JSON); + + assertThat(dataMap.getFormData()).doesNotContainKey(FormSolutionsAttachmentsMapper.ZIP); + } + + @Test + void shouldRemovePdf() { + var formData = FormDataTestFactory.withFormDataMaps(Map.of(FormSolutionsRepresentationsMapper.PDF, "test")); + + var dataMap = mapper.mapFiles(formData, ATTACHMENTS_JSON); + + assertThat(dataMap.getFormData()).doesNotContainKey(FormSolutionsRepresentationsMapper.PDF); + } + } - @SuppressWarnings("unchecked") - private List<Map<String, Object>> getNestedComponents(FormData dataMap) { - return (List<Map<String, Object>>) ((List<Map<String, Object>>) getPanels(dataMap).get(0).get(COMPONENTS)).get(0).get(COMPONENTS); } } diff --git a/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/SendFormEndpointITCase.java b/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/SendFormEndpointITCase.java index 0272bbf580cffe9b032b6d1ba4677ea9ee473214..6f0083b92edca24db4f01333c735b79f9119986a 100644 --- a/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/SendFormEndpointITCase.java +++ b/formsolutions-adapter/src/test/java/de/itvsh/kop/eingangsadapter/formsolutions/SendFormEndpointITCase.java @@ -158,7 +158,7 @@ class SendFormEndpointITCase { @SuppressWarnings("unchecked") private IncomingFile getRepresentation(Map<String, Object> data) { - return ((List<IncomingFile>) ((Map<String, Object>) data.get(MAPPED_FILES)).get(PARSED_REPRESENTATIONS)).get(0); + return ((List<IncomingFile>) ((Map<String, Object>) data.get(FIELD_NAME_MAPPED_FILES)).get(PARSED_REPRESENTATIONS)).get(0); } } @@ -189,6 +189,6 @@ class SendFormEndpointITCase { @SuppressWarnings("unchecked") private Map<String, Object> getFiles(Map<String, Object> data) { - return (Map<String, Object>) data.get(MAPPED_FILES); + return (Map<String, Object>) data.get(FIELD_NAME_MAPPED_FILES); } } diff --git a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerMapper.java b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerMapper.java deleted file mode 100644 index 52b065cb2dfc9b79693c1a89cbcdafa09fa9a83c..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerMapper.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.intelliform; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import org.springframework.stereotype.Component; - -import de.itvsh.kop.eingangsadapter.common.formdata.Antragsteller; -import de.itvsh.kop.eingangsadapter.common.formdata.Antragsteller.AntragstellerBuilder; - -@Component -class AntragstellerMapper { - - static final String XML_ANTRAGSTELLER = "antragsteller"; - - static final String XML_MAPPING_ANREDE = "b_anrede"; - static final String XML_MAPPING_VORNAME = "pers_vorname"; - static final String XML_MAPPING_NACHNAME = "pers_nachname"; - static final String XML_MAPPING_GEBURTSNAME = "pers_geburtsname"; - static final String XML_MAPPING_GEBURTSDATUM = "pers_geburtsdatum"; - static final String XML_MAPPING_GEBURTSORT = "pers_geburtsort"; - static final String XML_MAPPING_EMAIL = "kont_email"; - static final String XML_MAPPING_TELEFON = "kont_telefonnummer"; - - static final String XML_MAPPING_STRASSE = "sh_strasse"; - static final String XML_MAPPING_HAUSNUMMER = "sh_hausnummer"; - static final String XML_MAPPING_PLZ = "sh_plz"; - static final String XML_MAPPING_ORT = "ort"; - - static final String XML_MAPPING_POSTFACH_ID = "nameid"; - - private static final Set<String> XML_MAPPINGS = new HashSet<>(List.of( - XML_MAPPING_ANREDE, - XML_MAPPING_VORNAME, - XML_MAPPING_NACHNAME, - XML_MAPPING_GEBURTSNAME, - XML_MAPPING_GEBURTSDATUM, - XML_MAPPING_GEBURTSORT, - XML_MAPPING_EMAIL, - XML_MAPPING_TELEFON, - XML_MAPPING_STRASSE, - XML_MAPPING_HAUSNUMMER, - XML_MAPPING_PLZ, - XML_MAPPING_ORT, - XML_MAPPING_POSTFACH_ID)); - - public Antragsteller mapToAntragsteller(Map<String, Object> formDataMap) { - var builder = Antragsteller.builder().postfachId(getPostfachId(formDataMap)); - - var filledBuilder = getAntragstellerMap(formDataMap) - .map(antragstellerMap -> addAntragstellerData(builder, antragstellerMap)) - .orElse(builder); - - removeMappedData(formDataMap); - return filledBuilder.build(); - } - - private String getPostfachId(Map<String, Object> formDataMap) { - return (String) formDataMap.get(XML_MAPPING_POSTFACH_ID); - } - - @SuppressWarnings("unchecked") - private Optional<Map<String, Object>> getAntragstellerMap(Map<String, Object> formDataMap) { - return Optional.ofNullable(formDataMap.get(XML_ANTRAGSTELLER)).map(Map.class::cast).map(HashMap::new); - } - - private AntragstellerBuilder addAntragstellerData(AntragstellerBuilder builder, Map<String, Object> antragstellerMap) { - return builder // - .anrede((String) antragstellerMap.get(XML_MAPPING_ANREDE)) // - .vorname((String) antragstellerMap.get(XML_MAPPING_VORNAME)) // - .nachname((String) antragstellerMap.get(XML_MAPPING_NACHNAME)) // - .geburtsname((String) antragstellerMap.get(XML_MAPPING_GEBURTSNAME)) // - .geburtsdatum((String) antragstellerMap.get(XML_MAPPING_GEBURTSDATUM)) // - .geburtsort((String) antragstellerMap.get(XML_MAPPING_GEBURTSORT)) // - .email((String) antragstellerMap.get(XML_MAPPING_EMAIL)) // - .telefon((String) antragstellerMap.get(XML_MAPPING_TELEFON)) // - .strasse((String) antragstellerMap.get(XML_MAPPING_STRASSE)) // - .hausnummer((String) antragstellerMap.get(XML_MAPPING_HAUSNUMMER)) // - .plz((String) antragstellerMap.get(XML_MAPPING_PLZ)) // - .ort((String) antragstellerMap.get(XML_MAPPING_ORT)) // - .data(getNotMappedData(antragstellerMap)); - } - - private Map<String, Object> getNotMappedData(Map<String, Object> antragstellerMap) { - var tempMap = new HashMap<>(antragstellerMap); - XML_MAPPINGS.forEach(tempMap::remove); - return tempMap; - } - - private void removeMappedData(Map<String, Object> formDataMap) { - formDataMap.remove(XML_ANTRAGSTELLER); - formDataMap.remove(XML_MAPPING_POSTFACH_ID); - } -} \ No newline at end of file diff --git a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapper.java b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapper.java index caad9cd7a5e65a2630d04585ea69c42d1b4774ba..7810c2ef5c918e971e13243c9951ff8dcbf028f7 100644 --- a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapper.java +++ b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapper.java @@ -26,6 +26,7 @@ package de.itvsh.kop.eingangsadapter.intelliform; import static de.itvsh.kop.eingangsadapter.semantik.enginebased.AbstractFileMapper.*; import java.io.ByteArrayInputStream; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,6 +42,7 @@ import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFile; import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileGroup; import lombok.RequiredArgsConstructor; +//TODO Naming prüfen - er scheint mir nicht semantik zu mappen und befindet sich auch nicht im entsprechenden Modul @Component @RequiredArgsConstructor class SemantikFormDataMapper { @@ -94,7 +96,7 @@ class SemantikFormDataMapper { addHeader(document, formDataMap); - return FormData.builder().formData(formDataMap).build(); + return FormData.builder().formData(Collections.unmodifiableMap(formDataMap)).build(); } private byte[] getXmlFormData(DepositData depositData) { @@ -111,7 +113,7 @@ class SemantikFormDataMapper { List<IncomingFile> representations = incomingFilesService.calculateRepresentations(attachments, depositRequestFiles); - formDataMap.put(MAPPED_FILES, Map.of( + formDataMap.put(FIELD_NAME_MAPPED_FILES, Map.of( ATTACHMENTS, attachments, REPRESENTATIONS, representations)); diff --git a/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerMapperTest.java b/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerMapperTest.java deleted file mode 100644 index 9c6817654276444b228d035bfd95c8e686815618..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerMapperTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.intelliform; - -import static org.assertj.core.api.Assertions.*; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -class AntragstellerMapperTest { - - private final static AntragstellerMapper mapper = new AntragstellerMapper(); - - @Nested - class TestMapToAntragsteller { - - @Test - void shouldMapFields() { - var antragsteller = mapper.mapToAntragsteller(createDataMap()); - - assertThat(antragsteller).usingRecursiveComparison().ignoringFields("data").isEqualTo(AntragstellerTestFactory.create()); - } - - @Test - void shouldMapPostfachId() { - var antragsteller = mapper.mapToAntragsteller(createDataMap()); - - assertThat(antragsteller.getPostfachId()).isEqualTo(AntragstellerTestFactory.POSTFACH_ID); - } - - @Nested - class TestOtherData { - - private final String NOT_MAPPED_FIELD_KEY = "NotMappedField"; - - @Test - void shouldNotContainDuplicateValues() { - var antragsteller = mapper.mapToAntragsteller(createDataMap()); - - assertThat(antragsteller.getData()).doesNotContainKeys( - AntragstellerMapper.XML_MAPPING_ANREDE, - AntragstellerMapper.XML_MAPPING_EMAIL, - AntragstellerMapper.XML_MAPPING_GEBURTSDATUM, - AntragstellerMapper.XML_MAPPING_GEBURTSNAME, - AntragstellerMapper.XML_MAPPING_GEBURTSORT, - AntragstellerMapper.XML_MAPPING_NACHNAME, - AntragstellerMapper.XML_MAPPING_VORNAME, - AntragstellerMapper.XML_MAPPING_TELEFON, - AntragstellerMapper.XML_MAPPING_STRASSE, - AntragstellerMapper.XML_MAPPING_HAUSNUMMER, - AntragstellerMapper.XML_MAPPING_ORT, - AntragstellerMapper.XML_MAPPING_PLZ); - } - - @Test - void shouldContainNotMappedData() { - var antragstellerMap = new HashMap<>(AntragstellerTestFactory.createAsMap()); - antragstellerMap.put(NOT_MAPPED_FIELD_KEY, "Value!"); - var antragsteller = mapper.mapToAntragsteller(createDataMap(antragstellerMap)); - - assertThat(antragsteller.getData()).containsKey(NOT_MAPPED_FIELD_KEY); - } - } - - private Map<String, Object> createDataMap() { - return createDataMap(AntragstellerTestFactory.createAsMap()); - } - - private Map<String, Object> createDataMap(Map<String, Object> antragstellerMap) { - Map<String, Object> dataMap = new HashMap<>(); - dataMap.put(AntragstellerMapper.XML_ANTRAGSTELLER, antragstellerMap); - dataMap.put(AntragstellerMapper.XML_MAPPING_POSTFACH_ID, AntragstellerTestFactory.POSTFACH_ID); - return dataMap; - } - } -} \ No newline at end of file diff --git a/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerTestFactory.java b/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerTestFactory.java deleted file mode 100644 index 0a6bf40d8ea0d5963f7ed7f9a70e5b60c83df4f8..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/AntragstellerTestFactory.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.intelliform; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import de.itvsh.kop.eingangsadapter.common.formdata.Antragsteller; - -public class AntragstellerTestFactory { - - static final String ANREDE = "Herr"; - static final String VORNAME = "Max"; - static final String NACHNAME = "Mustermann"; - static final String GEBURTSNAME = "Maxi"; - static final String GEBURTSDATUM = "01.01.1970"; - static final String GEBURTSORT = "Sandhausen"; - static final String EMAIL = "alsob@ne.ver"; - static final String TELEFON = "+ 49 4621 9654"; - - static final String STRASSE = "Lachstrasse"; - static final String HAUSNUMMER = "8484"; - static final String PLZ = "12345"; - static final String ORT = "Wohlfuehlhausen"; - - static final String POSTFACH_ID = UUID.randomUUID().toString(); - - public static Antragsteller create() { - return createBuilder().build(); - } - - public static Antragsteller.AntragstellerBuilder createBuilder() { - return Antragsteller.builder() - .anrede(ANREDE) - .vorname(VORNAME) - .nachname(NACHNAME) - .geburtsname(GEBURTSNAME) - .geburtsdatum(GEBURTSDATUM) - .geburtsort(GEBURTSORT) - .email(EMAIL) - .telefon(TELEFON) - .strasse(STRASSE) - .hausnummer(HAUSNUMMER) - .plz(PLZ) - .ort(ORT) - .postfachId(POSTFACH_ID); - } - - public static Map<String, Object> createAsMap() { - var map = new HashMap<String, Object>(); - map.put(AntragstellerMapper.XML_MAPPING_ANREDE, ANREDE); - map.put(AntragstellerMapper.XML_MAPPING_VORNAME, VORNAME); - map.put(AntragstellerMapper.XML_MAPPING_NACHNAME, NACHNAME); - map.put(AntragstellerMapper.XML_MAPPING_GEBURTSNAME, GEBURTSNAME); - map.put(AntragstellerMapper.XML_MAPPING_GEBURTSDATUM, GEBURTSDATUM); - map.put(AntragstellerMapper.XML_MAPPING_GEBURTSORT, GEBURTSORT); - map.put(AntragstellerMapper.XML_MAPPING_EMAIL, EMAIL); - map.put(AntragstellerMapper.XML_MAPPING_TELEFON, TELEFON); - map.put(AntragstellerMapper.XML_MAPPING_STRASSE, STRASSE); - map.put(AntragstellerMapper.XML_MAPPING_HAUSNUMMER, HAUSNUMMER); - map.put(AntragstellerMapper.XML_MAPPING_PLZ, PLZ); - map.put(AntragstellerMapper.XML_MAPPING_ORT, ORT); - return map; - } -} \ No newline at end of file diff --git a/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapperTest.java b/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapperTest.java index 42603a449d1ab72777faaa0dd9133aa4d0682a68..66260ae807040cfe7b6d6f2a18b25d77ef9ec349 100644 --- a/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapperTest.java +++ b/intelliform-adapter/src/test/java/de/itvsh/kop/eingangsadapter/intelliform/SemantikFormDataMapperTest.java @@ -27,6 +27,7 @@ import static de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileGroupTest import static org.assertj.core.api.Assertions.*; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,13 +60,11 @@ class SemantikFormDataMapperTest { @Test void shouldRemoveFileReferences() { - var formData = mapToFormData(deposit); - - formData.getFormData().put(FILE_REF1, Map.of(SemantikFormDataMapper.FILE, Map.of(ID, VENDOR_ID_XXX))); + Map<String, Object> formDataMap = new HashMap<>(Map.of(FILE_REF1, Map.of(SemantikFormDataMapper.FILE, Map.of(ID, VENDOR_ID_XXX)))); - mapper.removeMappedFileReferences(FILE_GROUPS, formData.getFormData()); + mapper.removeMappedFileReferences(FILE_GROUPS, formDataMap); - assertThat(formData.getFormData()).doesNotContainKey(FILE_REF1); + assertThat(formDataMap).doesNotContainKey(FILE_REF1); } @Nested @@ -112,7 +111,7 @@ class SemantikFormDataMapperTest { @SuppressWarnings("unchecked") private List<IncomingFile> getRepresentations(FormData formData) { - return (List<IncomingFile>) ((Map<String, Object>) formData.getFormData().get(AbstractFileMapper.MAPPED_FILES)) + return (List<IncomingFile>) ((Map<String, Object>) formData.getFormData().get(AbstractFileMapper.FIELD_NAME_MAPPED_FILES)) .get(AbstractFileMapper.REPRESENTATIONS); } } diff --git a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/IncomingFileGroupMapper.java b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/IncomingFileGroupMapper.java deleted file mode 100644 index 637d3c9cd885e1e9f0c3fda6fecb1ee0a7a02d10..0000000000000000000000000000000000000000 --- a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/IncomingFileGroupMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.router; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileGroup; -import de.itvsh.ozg.pluto.vorgang.GrpcIncomingFileGroup; - -@Mapper(uses = IncomingFileMapper.class) -interface IncomingFileGroupMapper { - - @Mapping(source = "files", target = "filesList") - GrpcIncomingFileGroup mapToGrpc(IncomingFileGroup fileGroup); -} \ No newline at end of file diff --git a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/IncomingFileMapper.java b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/IncomingFileMapper.java deleted file mode 100644 index 1c81c7bf7ad57f3a446b846097cf37d39b603d67..0000000000000000000000000000000000000000 --- a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/IncomingFileMapper.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.router; - -import org.mapstruct.Mapper; - -import com.google.protobuf.ByteString; - -import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFile; -import de.itvsh.ozg.pluto.vorgang.GrpcIncomingFile; - -@Mapper(uses = FileIdMapper.class) -interface IncomingFileMapper { - - GrpcIncomingFile mapToGrpc(IncomingFile file); - - default ByteString map(byte[] value) { - return ByteString.copyFrom(value); - } -} \ No newline at end of file diff --git a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/IncomingFileGroupMapperTest.java b/router/src/test/java/de/itvsh/kop/eingangsadapter/router/IncomingFileGroupMapperTest.java deleted file mode 100644 index 83deb974084426ce88392ce15408ff4715033e9e..0000000000000000000000000000000000000000 --- a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/IncomingFileGroupMapperTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.router; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mapstruct.factory.Mappers; -import org.mockito.InjectMocks; -import org.mockito.Spy; - -import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileGroupTestFactory; - -class IncomingFileGroupMapperTest { - - @InjectMocks - private IncomingFileGroupMapper fileGroupMapper = Mappers.getMapper(IncomingFileGroupMapper.class); - @Spy - private IncomingFileMapper fileMapper = Mappers.getMapper(IncomingFileMapper.class); - - @Disabled - @Nested - class TestIncomingFileGroupMapper { - - @Test - void shouldMap() { - var mappedValue = fileGroupMapper.mapToGrpc(IncomingFileGroupTestFactory.create()); - - assertThat(mappedValue.getFilesList()).hasSize(1); - assertThat(mappedValue.getFiles(0)).usingRecursiveComparison().isEqualTo(GrpcIncomingFileTestFactory.create()); - } - } -} \ No newline at end of file diff --git a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/IncomingFileMapperTest.java b/router/src/test/java/de/itvsh/kop/eingangsadapter/router/IncomingFileMapperTest.java deleted file mode 100644 index 309d63db3239302f643ad6f7cc886f3c99818d1f..0000000000000000000000000000000000000000 --- a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/IncomingFileMapperTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.itvsh.kop.eingangsadapter.router; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mapstruct.factory.Mappers; -import org.mockito.InjectMocks; - -import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileTestFactory; - -class IncomingFileMapperTest { - - @InjectMocks - private IncomingFileMapper mapper = Mappers.getMapper(IncomingFileMapper.class); - - @Nested - class TestGrpcIncomingFileMapToIncomingFile { - - @Test - void shouldMap() { - var result = mapper.mapToGrpc(IncomingFileTestFactory.create()); - - assertThat(result).isNotNull().usingRecursiveComparison().isEqualTo(GrpcIncomingFileTestFactory.create()); - } - } -} \ No newline at end of file diff --git a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/SemantikAdapter.java b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/SemantikAdapter.java index 9d228e3cff3ab2b538ec9373a4a21713701022c7..0cdf2991d73c8a57ab8eb3a92db137acfbfea029 100644 --- a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/SemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/SemantikAdapter.java @@ -42,7 +42,7 @@ public class SemantikAdapter { @Autowired private VorgangService vorgangService; - public void processFormDGata(FormData formData) { + public void processFormData(FormData formData) { formData = parseByEngineAdapter(formData); formData = parseByFormAdapter(formData); diff --git a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AbstractFileMapper.java b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AbstractFileMapper.java index 6b4ab4bcda54ca77384c7d9c27a9c60d2abce119..7ecc4e99b103ba2dab46466a93a0a106a0c0d37f 100644 --- a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AbstractFileMapper.java +++ b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AbstractFileMapper.java @@ -23,19 +23,20 @@ */ package de.itvsh.kop.eingangsadapter.semantik.enginebased; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormDataUtils; import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFile; import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileGroup; +//TODO Vererbung ausbauen und durch Utils ersetzen public abstract class AbstractFileMapper implements EngineBasedMapper { public static final String ATTACHMENTS = "parsedAttachments"; public static final String REPRESENTATIONS = "parsedRepresentations"; - public static final String MAPPED_FILES = "mappedFiles"; + public static final String FIELD_NAME_MAPPED_FILES = "mappedFiles"; @Override public FormData parseFormData(FormData formData) { @@ -76,16 +77,13 @@ public abstract class AbstractFileMapper implements EngineBasedMapper { return builder; } - @SuppressWarnings("unchecked") protected Map<String, Object> getMappedFiles(FormData formData) { - return (Map<String, Object>) formData.getFormData().get(MAPPED_FILES); + return FormDataUtils.getSubMap(formData, FIELD_NAME_MAPPED_FILES); } protected FormData removeProcessedData(FormData formData) { - Map<String, Object> mutableMap = new HashMap<>(formData.getFormData()); - mutableMap.remove(MAPPED_FILES); + return FormDataUtils.from(formData).remove(FIELD_NAME_MAPPED_FILES).build(); // TODO copyOf erlaubt keine null values -daher ausbauen - return formData.toBuilder().formData(Map.copyOf(mutableMap)).build(); - } -} + } +} \ No newline at end of file diff --git a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapper.java b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapper.java index 9b68182489cf89049a9a5550fa2837136d98c907..5aea6ce1d47d063f9a596ec96ecb41754b6b81a1 100644 --- a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapper.java +++ b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapper.java @@ -35,64 +35,75 @@ import org.springframework.stereotype.Component; import de.itvsh.kop.eingangsadapter.common.formdata.Antragsteller; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormDataUtils; @Component public class FormSolutionsAntragstellerMapper implements FormSolutionsEngineBasedMapper { + public static final String ANTRAGSTELLER_PANEL_IDENTIFIER = "Antragstellende Person"; + public static final String POSTKORBHANDLE = "postkorbhandle"; + public static final String VORNAME_KEY = "AS_Vorname"; public static final String NACHNAME_KEY = "AS_Name"; @Override public FormData parseFormData(FormData formData) { - var cleanedData = removePostkorbhandle(formData); - - Antragsteller.AntragstellerBuilder builder = Antragsteller.builder() - .postfachId((String) formData.getFormData().get(POSTKORBHANDLE)); + return FormDataUtils.from(formData) + .remove(POSTKORBHANDLE) + .builder() + .antragsteller(buildAntragsteller(formData)) + .build(); + } + Antragsteller buildAntragsteller(FormData formData) { var antragstellerData = findAntragstellerData(formData.getFormData()); - findValueByKey(NACHNAME_KEY, antragstellerData).ifPresent(builder::nachname); + return Antragsteller.builder() + .postfachId(getPostkorbhandle(formData)) + .vorname(getVorname(antragstellerData)) + .nachname(getNachname(antragstellerData)) + .build(); + } + + private String getVorname(Map<String, String> antragstellerData) { + return Optional.ofNullable(antragstellerData.get(VORNAME_KEY)).orElse(null); + } - findValueByKey(VORNAME_KEY, antragstellerData).ifPresent(builder::vorname); + private String getNachname(Map<String, String> antragstellerData) { + return Optional.ofNullable(antragstellerData.get(NACHNAME_KEY)).orElse(null); + } - return formData.toBuilder() - .antragsteller(builder.build()) - .formData(cleanedData) - .build(); + private String getPostkorbhandle(FormData formData) { + return (String) formData.getFormData().get(POSTKORBHANDLE); } - // TODO auf immutable ma umstellen private Map<String, String> findAntragstellerData(Map<String, Object> formData) { - Map<String, String> names = new HashMap<>(); - addContent(getPanels(formData), names); + var names = new HashMap<String, String>(); + addContent(getAssistantPanels(formData), names); return names; } - private Optional<String> findValueByKey(String key, Map<String, String> data) { - return Optional.ofNullable(data.get(key)); + private void addContent(List<Map<String, Object>> panels, Map<String, String> names) { + panels.stream().forEach(entry -> handleContentEntry(entry, names)); } - @SuppressWarnings("unchecked") - private List<Map<String, Object>> getPanels(Map<String, Object> formData) { - return ((List<Map<String, Object>>) ((Map<String, Object>) formData.get(ASSISTANT)).get(PANELS)); + private void handleContentEntry(Map<String, Object> entry, Map<String, String> names) { + if (entry.containsKey(COMPONENTS)) { + addContent(getComponentList(entry), names); + } else if (entry.containsKey(STRING_VALUE)) { + names.put((String) entry.get(IDENTIFIER), (String) entry.get(STRING_VALUE)); + } } @SuppressWarnings("unchecked") - private void addContent(List<Map<String, Object>> items, Map<String, String> names) { - items.stream().forEach(entry -> { - if (entry.containsKey(COMPONENTS)) { - addContent((List<Map<String, Object>>) entry.get(COMPONENTS), names); - } else if (entry.containsKey(STRING_VALUE)) { - names.put((String) entry.get(IDENTIFIER), (String) entry.get(STRING_VALUE)); - } - }); + private List<Map<String, Object>> getComponentList(Map<String, Object> entry) { + return (List<Map<String, Object>>) entry.get(COMPONENTS); } - private Map<String, Object> removePostkorbhandle(FormData processedData) { - Map<String, Object> cleanedData = new HashMap<>(processedData.getFormData()); - cleanedData.remove(POSTKORBHANDLE); - return cleanedData; + @SuppressWarnings("unchecked") + private List<Map<String, Object>> getAssistantPanels(Map<String, Object> formData) { + return ((List<Map<String, Object>>) ((Map<String, Object>) formData.get(ASSISTANT)).get(PANELS)); } } diff --git a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapter.java b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapter.java index 4ca23cd04339e284416000190b190b30100206a3..99e0b79f7af4fc813d9785c985e7379d725992d9 100644 --- a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapter.java +++ b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapter.java @@ -28,9 +28,12 @@ import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormDataUtils; public class FormSolutionsEngineBasedAdapter implements EngineBasedSemantikAdapter { + public static final String IDENTIFIER = "identifier"; + public static final String ASSISTANT = "assistant"; public static final String ANLIEGEN_ID = "anliegenId"; public static final String KOMMUNALVERWALTUNG_ID = "kommunalverwaltungId"; @@ -42,18 +45,18 @@ public class FormSolutionsEngineBasedAdapter implements EngineBasedSemantikAdapt public FormData parseFormData(FormData formData) { var processedFormData = formData; - for (FormSolutionsEngineBasedMapper mapper : mappers) { + for (var mapper : mappers) { processedFormData = mapper.parseFormData(processedFormData); } - removeProcessedRawData(processedFormData); - - return processedFormData; + return removeProcessedData(processedFormData); } - void removeProcessedRawData(FormData processedFormData) { - processedFormData.getFormData().remove(ASSISTANT); - processedFormData.getFormData().remove(ANLIEGEN_ID); - processedFormData.getFormData().remove(KOMMUNALVERWALTUNG_ID); + FormData removeProcessedData(FormData formData) { + return FormDataUtils.from(formData) + .remove(ASSISTANT) + .remove(ANLIEGEN_ID) + .remove(KOMMUNALVERWALTUNG_ID) + .build(); } } diff --git a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapper.java b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapper.java index ac13ff44b619fd9bdb49f616647edf7a380dedba..bff02b1339ced485bfb2d26cc2d1c7686834b6e4 100644 --- a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapper.java +++ b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapper.java @@ -25,12 +25,12 @@ package de.itvsh.kop.eingangsadapter.semantik.enginebased; import static de.itvsh.kop.eingangsadapter.semantik.enginebased.FormSolutionsEngineBasedAdapter.*; -import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Component; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormDataUtils; import de.itvsh.kop.eingangsadapter.common.formdata.FormHeader; @Component @@ -38,33 +38,40 @@ public class FormSolutionsHeaderMapper implements FormSolutionsEngineBasedMapper static final String TRANSACTION_ID = "transactionId"; - static final String FS_FORMENGINE_NAME = "FormSolutions"; + static final String FORM_ENGINE_NAME = "FormSolutions"; @Override public FormData parseFormData(FormData formData) { - var header = mapHeader(formData); - var cleanedData = removeTransactionId(formData); + return FormDataUtils.from(formData) + .remove(TRANSACTION_ID) + .builder() + .header(buildFormHeader(formData)) + .build(); + } - return formData.toBuilder().header(header).formData(cleanedData).build(); + FormHeader buildFormHeader(FormData formData) { + return FormHeader.builder() + .formName(getIdentifier(formData)) + .formId(getIdentifier(formData)) + .requestId(getRequestId(formData)) + .formEngineName(FORM_ENGINE_NAME) + .build(); } - private Map<String, Object> removeTransactionId(FormData processedData) { - Map<String, Object> cleanedData = new HashMap<>(processedData.getFormData()); - cleanedData.remove(TRANSACTION_ID); + private String getIdentifier(FormData formData) { + return (String) getAssistant(formData).get(IDENTIFIER); // TODO immutable machen - return cleanedData; } - @SuppressWarnings("unchecked") - FormHeader mapHeader(FormData formData) { - var assistantMap = (Map<String, Object>) formData.getFormData().get(ASSISTANT); + private String getRequestId(FormData formData) { + return (String) formData.getFormData().get(TRANSACTION_ID); + } - return FormHeader.builder() - .formName((String) assistantMap.get(IDENTIFIER)) - .formId((String) assistantMap.get(IDENTIFIER)) - .requestId((String) formData.getFormData().get(TRANSACTION_ID)) - .formEngineName(FS_FORMENGINE_NAME) - .build(); + private Map<String, Object> getAssistant(FormData formData) { + return FormDataUtils.getSubMap(formData, ASSISTANT); } + Map<String, Object> removeProcessedData(FormData processedData) { + return FormDataUtils.from(processedData).remove(TRANSACTION_ID).build().getFormData(); + } } diff --git a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapper.java b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapper.java index b0b1952fa4c2dcfc57459b324bf24b2eb2d2ffb3..04e113b811fa6ee64e0425ea799eba65d55b9d71 100644 --- a/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapper.java +++ b/semantik-adapter/src/main/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapper.java @@ -23,6 +23,7 @@ */ package de.itvsh.kop.eingangsadapter.semantik.enginebased; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -33,21 +34,31 @@ import de.itvsh.kop.eingangsadapter.common.formdata.ZustaendigeStelle; @Component public class FormSolutionsZustaendigeStelleMapper implements FormSolutionsEngineBasedMapper { + public static final String ZUSTAENDIGE_STELLE = "zustaendigeStelle"; @Override public FormData parseFormData(FormData formData) { - var zustaendigeStelle = ZustaendigeStelle.builder().organisationseinheitenId((String) formData.getFormData().get(ZUSTAENDIGE_STELLE)).build(); + return formData.toBuilder() + .zustaendigeStelle(buildZustaendigeStelle(formData)) + .formData(removeProcessedData(formData)) + .build(); + } - var cleanData = removeZustaendigeStelle(formData); + ZustaendigeStelle buildZustaendigeStelle(FormData formData) { + return ZustaendigeStelle.builder() + .organisationseinheitenId(getZustaenigeStelle(formData)) + .build(); + } - return formData.toBuilder().zustaendigeStelle(zustaendigeStelle).formData(cleanData).build(); + private String getZustaenigeStelle(FormData formData) { + return (String) formData.getFormData().get(ZUSTAENDIGE_STELLE); } - private Map<String, Object> removeZustaendigeStelle(FormData formData) { - var cleanedData = new HashMap<>(formData.getFormData()); + Map<String, Object> removeProcessedData(FormData formData) { + var cleanedData = new HashMap<String, Object>(formData.getFormData()); cleanedData.remove(ZUSTAENDIGE_STELLE); - // TODO immutable machen - return cleanedData; + + return Collections.unmodifiableMap(cleanedData); } -} +} \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmFilesMapperTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmFilesMapperTest.java index 6134fe90f49e14a3046a27ce185d13f1c127374a..f2ab3e95d9ffaeb76fb16434079aebdbded5175b 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmFilesMapperTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmFilesMapperTest.java @@ -52,7 +52,7 @@ class AfmFilesMapperTest { private FormData formData = FormDataTestFactory.createBuilder() .clearAttachments() - .formData(Map.of(AbstractFileMapper.MAPPED_FILES, + .formData(Map.of(AbstractFileMapper.FIELD_NAME_MAPPED_FILES, Map.of(AbstractFileMapper.ATTACHMENTS, List.of(IncomingFileGroupTestFactory.create(), attachmentWithMultipleFiles)))) .build(); @@ -93,7 +93,7 @@ class AfmFilesMapperTest { void shouldRemoveFilesFromMap() { var parsedFormData = parseFormData(); - assertThat(parsedFormData.getFormData().get(AbstractFileMapper.MAPPED_FILES)).isNull(); + assertThat(parsedFormData.getFormData().get(AbstractFileMapper.FIELD_NAME_MAPPED_FILES)).isNull(); } private FormData parseFormData() { diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmZustaendigeStelleMapperTest.java index 483c26f53553cdeaee6c60b384d021b442b20114..79c53555884a8df252546823046c1fff4b9bacfa 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AfmZustaendigeStelleMapperTest.java @@ -28,10 +28,7 @@ import static org.mockito.Mockito.*; import java.util.HashMap; import java.util.Map; -import java.util.UUID; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -158,72 +155,6 @@ class AfmZustaendigeStelleMapperTest { } } - @Disabled - @Nested - class TestRemoveFields { - - @Nested - class TestWithMappedValueOnly { - - private FormData formData = FormData.builder().formData(AfmZustaendigeStelleTestFactory.createFormDataMap()).build(); - - @Test - void shouldRemoveZustaendigeStelle() { - var parsedFormData = parseFormData(formData); - - assertThat(parsedFormData.getFormData().get(AfmZustaendigeStelleMapper.ZUSTAENDIGESTELLE)).isNull(); - } - } - - @Nested - class TestWithMappedAndNotMappedValue { - - private static final String NOT_MAPPED_FIELD = "not_mapping_value"; - private static final String NOT_MAPPED_VALUE = UUID.randomUUID().toString(); - - private FormData formData; - - @BeforeEach - void buildFormData() { - var zustaendigeStelleMap = AfmZustaendigeStelleTestFactory.createZustaendigeStelleMap(); - zustaendigeStelleMap.put(NOT_MAPPED_FIELD, NOT_MAPPED_VALUE); - var formDataMap = new HashMap<String, Object>(); - formDataMap.put(AfmZustaendigeStelleMapper.ZUSTAENDIGESTELLE, zustaendigeStelleMap); - - formData = FormData.builder().formData(formDataMap).build(); - } - - @Test - void shouldRemoveOrganisationseinheitenId() { - var parsedFormData = parseFormData(formData); - - var zustaendigeStelle = getZustaendigeStelleMap(parsedFormData); - assertThat(zustaendigeStelle.get(AfmZustaendigeStelleMapper.ORGANISATIONSEINHEITEN_ID)).isNull(); - } - - @Test - void shouldRemoveEmail() { - var parsedFormData = parseFormData(formData); - - var zustaendigeStelle = getZustaendigeStelleMap(parsedFormData); - assertThat(zustaendigeStelle.get(AfmZustaendigeStelleMapper.EMAIL)).isNull(); - } - - @Test - void shouldKeepNotMappedField() { - var parsedFormData = parseFormData(formData); - - var zustaendigeStelle = getZustaendigeStelleMap(parsedFormData); - assertThat(zustaendigeStelle).containsEntry(NOT_MAPPED_FIELD, NOT_MAPPED_VALUE); - } - - @SuppressWarnings("unchecked") - private Map<String, Object> getZustaendigeStelleMap(FormData formData) { - return (Map<String, Object>) formData.getFormData().get(AfmZustaendigeStelleMapper.ZUSTAENDIGESTELLE); - } - } - } - private FormData parseFormData(FormData formData) { return mapper.parseFormData(formData); } diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AttachmentsTestFactory.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AttachmentsTestFactory.java index b7b63be590099e4e0e170fa050a289d53878fcc1..4b3d1f2c32537851ada9182bb4c6ff883b1a66d0 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AttachmentsTestFactory.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/AttachmentsTestFactory.java @@ -41,13 +41,13 @@ public class AttachmentsTestFactory { public static final String ZIP_ENCODED = "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"; public static final byte[] ZIP_DECODED = Base64.getDecoder().decode(ZIP_ENCODED.getBytes()); - +//TODO es bringt für den Tests nichts, den gleichen decoder zu verwenden wie im richtigen Code - umstellen auf vorkodierte Datei private static final String ZIP_ENCRYPTED_ENCODED = "UEsDBBQACQAIAGxbgVR2JDbWfAAAAJwAAAAJABwAc21hbGwudHh0VVQJAAN8xUZifMVGYnV4CwABBGJsYAsEAQJgC+UGqCf9nYnWPRIWHX3BIKiUYURrZACUULUIS//p8/GxbgqhmNJc9vvwM63ICih6zF75gd6jvEUvHKXrvjC5fz636xmuFoCmNjdFb0qs02H4llZkM7C5IF9raesJjK+Q6u/O7sAnIc2Qa677puRTGsHfxq7FYovFFy6xWSVQSwcIdiQ21nwAAACcAAAAUEsBAh4DFAAJAAgAbFuBVHYkNtZ8AAAAnAAAAAkAGAAAAAAAAQAAAKSBAAAAAHNtYWxsLnR4dFVUBQADfMVGYnV4CwABBGJsYAsEAQJgC1BLBQYAAAAAAQABAE8AAADPAAAAAAA="; public static final byte[] ZIP_ENCRYPTED_DECODED = Base64.getDecoder().decode(ZIP_ENCRYPTED_ENCODED.getBytes()); private static final String PDF_ENCODED = "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ZW5kb2JqCjI5IDAgb2JqCjw8L0NvbG9yU3BhY2UvRGV2aWNlR3JheS9TdWJ0eXBlL0ltYWdlL0hlaWdodCAxOS9GaWx0ZXIvRmxhdGVEZWNvZGUvVHlwZS9YT2JqZWN0L1dpZHRoIDE5L0xlbmd0aCAxMzIvQml0c1BlckNvbXBvbmVudCA4Pj5zdHJlYW0KeJxl0AENwCAMBMCXUAmTgAQkTMIkTEIdIGESkDAJSJgEJHQtDEKzTyDhUlqCyD83+9wijCVEYE+HSPQUtA97KiJ1c5S06HS9oo3HSvTYtU6Uc1DKWrSjk64asKtkfGSHulXdaFCbZImYhKtJwkLNCjmycQGeqMwX8/ivtP7XPy90XasiCmVuZHN0cmVhbQplbmRvYmoKMzAgMCBvYmoKPDwvQ29sb3JTcGFjZS9EZXZpY2VSR0IvU3VidHlwZS9JbWFnZS9IZWlnaHQgMTkvRmlsdGVyL0ZsYXRlRGVjb2RlL1R5cGUvWE9iamVjdC9XaWR0aCAxOS9TTWFzayAyOSAwIFIvTGVuZ3RoIDE4L0JpdHNQZXJDb21wb25lbnQgOD4+c3RyZWFtCnicY2AYBaNgFIwCkgEABDsAAQplbmRzdHJlYW0KZW5kb2JqCjMxIDAgb2JqCjw8L0NvbG9yU3BhY2UvRGV2aWNlR3JheS9TdWJ0eXBlL0ltYWdlL0hlaWdodCAxOS9GaWx0ZXIvRmxhdGVEZWNvZGUvVHlwZS9YT2JqZWN0L1dpZHRoIDE5L0xlbmd0aCAzMS9CaXRzUGVyQ29tcG9uZW50IDg+PnN0cmVhbQp4nPv/HxPsb0AF+///b2BABQ2jQgghLOGFCQANA2i1CmVuZHN0cmVhbQplbmRvYmoKMzIgMCBvYmoKPDwvQ29sb3JTcGFjZS9EZXZpY2VSR0IvU3VidHlwZS9JbWFnZS9IZWlnaHQgMTkvRmlsdGVyL0ZsYXRlRGVjb2RlL1R5cGUvWE9iamVjdC9XaWR0aCAxOS9TTWFzayAzMSAwIFIvTGVuZ3RoIDE4L0JpdHNQZXJDb21wb25lbnQgOD4+c3RyZWFtCnicY2AYBaNgFIwCkgEABDsAAQplbmRzdHJlYW0KZW5kb2JqCjMzIDAgb2JqCjw8L0NvbG9yU3BhY2UvRGV2aWNlR3JheS9TdWJ0eXBlL0ltYWdlL0hlaWdodCAxOS9GaWx0ZXIvRmxhdGVEZWNvZGUvVHlwZS9YT2JqZWN0L1dpZHRoIDE5L0xlbmd0aCAzMS9CaXRzUGVyQ29tcG9uZW50IDg+PnN0cmVhbQp4nPv/HxPsb0AF+///b2BABQ2jQgghLOGFCQANA2i1CmVuZHN0cmVhbQplbmRvYmoKMzQgMCBvYmoKPDwvQ29sb3JTcGFjZS9EZXZpY2VSR0IvU3VidHlwZS9JbWFnZS9IZWlnaHQgMTkvRmlsdGVyL0ZsYXRlRGVjb2RlL1R5cGUvWE9iamVjdC9XaWR0aCAxOS9TTWFzayAzMyAwIFIvTGVuZ3RoIDE4L0JpdHNQZXJDb21wb25lbnQgOD4+c3RyZWFtCnicY2AYBaNgFIwCkgEABDsAAQplbmRzdHJlYW0KZW5kb2JqCjM1IDAgb2JqCjw8L0NvbG9yU3BhY2UvRGV2aWNlR3JheS9TdWJ0eXBlL0ltYWdlL0hlaWdodCAxOS9GaWx0ZXIvRmxhdGVEZWNvZGUvVHlwZS9YT2JqZWN0L1dpZHRoIDE5L0xlbmd0aCAxMzIvQml0c1BlckNvbXBvbmVudCA4Pj5zdHJlYW0KeJxl0AENwCAMBMCXUAmTgAQkTMIkTEIdIGESkDAJSJgEJHQtDEKzTyDhUlqCyD83+9wijCVEYE+HSPQUtA97KiJ1c5S06HS9oo3HSvTYtU6Uc1DKWrSjk64asKtkfGSHulXdaFCbZImYhKtJwkLNCjmycQGeqMwX8/ivtP7XPy90XasiCmVuZHN0cmVhbQplbmRvYmoKMzYgMCBvYmoKPDwvQ29sb3JTcGFjZS9EZXZpY2VSR0IvU3VidHlwZS9JbWFnZS9IZWlnaHQgMTkvRmlsdGVyL0ZsYXRlRGVjb2RlL1R5cGUvWE9iamVjdC9XaWR0aCAxOS9TTWFzayAzNSAwIFIvTGVuZ3RoIDE4L0JpdHNQZXJDb21wb25lbnQgOD4+c3RyZWFtCnicY2AYBaNgFIwCkgEABDsAAQplbmRzdHJlYW0KZW5kb2JqCjM3IDAgb2JqCjw8L1N1YnR5cGUvRm9ybS9GaWx0ZXIvRmxhdGVEZWNvZGUvVHlwZS9YT2JqZWN0L01hdHJpeFsxIDAgMCAxIDAgMF0vRm9ybVR5cGUgMS9SZXNvdXJjZXM8PC9Gb250PDwvSGVsdiAx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bHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAxMSAwIFI+Pi9GZiAwPj4KZW5kb2JqCjQ5IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoZmlsZVVybCkvVHlwZS9Bbm5vdC9WKGh0dHBzJTNBJTJGJTJGa3VuZGVudGVzdC5mb3JtLXNvbHV0aW9ucy5kZSUyRm1ldGFmb3JtJTJGRm9ybS1Tb2x1dGlvbnMlMkZzaWQlMkZhc3Npc3RhbnQlMkY2MWIyMDhlODY2ZGExMjM2NDRjOTdlNTYlM0ZhbmxpZWdlbklkJTNEMTIzNCUyNm9yZ2FuaXNhdGlvbnNlaW5oZWl0ZW5JRCUzRDkwMzAyMjklMjZrb21tdW5hbHZlcndhbHR1bmdJZCUzRDEwMDAwMDAwMCUyNmNvbnNlbnRDb21wbGV0ZSUzRHRydWUlMjZjYWNoZUlEJTNENGZiNmI2ZTAtMGYxYy00OTcwLWI5ZWQtZGJmMjQyZDMzM2Y5JTI2Y2l0aXplblBvcnRhbExvZ2luU3VjY2VzcyUzRHRydWUpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAxMiAwIFI+Pi9GZiAwPj4KZW5kb2JqCjUwIDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfVm9ybmFtZSkvVHlwZS9Bbm5vdC9WKFN1c2FubmUpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAxNSAwIFI+Pi9GZiAwPj4KZW5kb2JqCjUxIDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfTmFtZSkvVHlwZS9Bbm5vdC9WKEZpc2NoZXIpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAxNiAwIFI+Pi9GZiAwPj4KZW5kb2JqCjUyIDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfUnVmbmFtZSkvVHlwZS9Bbm5vdC9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gMTcgMCBSPj4vRmYgMD4+CmVuZG9iago1MyAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKEFTX09yZGVuc25hbWVfS3VlbnN0bGVybmFtZSkvVHlwZS9Bbm5vdC9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gMTggMCBSPj4vRmYgMD4+CmVuZG9iago1NCAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKHN0YWF0KS9UeXBlL0Fubm90L1YoREUpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAxOSAwIFI+Pi9GZiAwPj4KZW5kb2JqCjU1IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfUExaKS9UeXBlL0Fubm90L1YoMTIzNDUpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAyMCAwIFI+Pi9GZiAwPj4KZW5kb2JqCjU2IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfT3J0KS9UeXBlL0Fubm90L1YoS2llbCkvRiA2L0RBKC9IZWx2IDAgVGYgMCBnICkvRlQvVHgvRFI8PC9Gb250PDwvSGVsdiAxMCAwIFI+Pj4+L1JlY3RbMCAwIDAgMF0vQVA8PC9OIDIxIDAgUj4+L0ZmIDA+PgplbmRvYmoKNTcgMCBvYmoKPDwvQlM8PC9TL1MvVyAxPj4vU3VidHlwZS9XaWRnZXQvVChCdW5kZXNsYW5kKS9UeXBlL0Fubm90L0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAyMiAwIFI+Pi9GZiAwPj4KZW5kb2JqCjU4IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfU3RyYXNzZSkvVHlwZS9Bbm5vdC9WKEhhdXB0c3RyYd9lKS9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gMjMgMCBSPj4vRmYgMD4+CmVuZG9iago1OSAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKEFTX0hhdXNudW1tZXIpL1R5cGUvQW5ub3QvRiA2L0RBKC9IZWx2IDAgVGYgMCBnICkvRlQvVHgvRFI8PC9Gb250PDwvSGVsdiAxMCAwIFI+Pj4+L1JlY3RbMCAwIDAgMF0vQVA8PC9OIDI0IDAgUj4+L0ZmIDA+PgplbmRvYmoKNjAgMCBvYmoKPDwvQlM8PC9TL1MvVyAxPj4vU3VidHlwZS9XaWRnZXQvVChBU19UZWxlZm9uKS9UeXBlL0Fubm90L0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAyNSAwIFI+Pi9GZiAwPj4KZW5kb2JqCjYxIDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoQVNfRS1NYWlsKS9UeXBlL0Fubm90L1Yobm9yZXBseUBvemctc2guZGU=KS9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gMjYgMCBSPj4vRmYgMD4+CmVuZG9iago2MiAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKEFTX0ZheCkvVHlwZS9Bbm5vdC9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gMjcgMCBSPj4vRmYgMD4+CmVuZG9iago2MyAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKG9mc1hYMV9mcm9tX3NtYWlsMykvVHlwZS9Bbm5vdC9WKHN1c2FubmUuZmlzY2hlckBkYXRhcG9ydC5kZSkvRiA2L0RBKC9IZWx2IDAgVGYgMCBnICkvRlQvVHgvRFI8PC9Gb250PDwvSGVsdiAxMCAwIFI+Pj4+L1JlY3RbMCAwIDAgMF0vQVA8PC9OIDI4IDAgUj4+L0ZmIDA+PgplbmRvYmoKNjQgMCBvYmoKPDwvQlM8PC9TL1MvVyAxPj4vU3VidHlwZS9XaWRnZXQvVChIdW5kX05hbWUpL1R5cGUvQW5ub3QvVihIYXNzbykvRiA2L0RBKC9IZWx2IDAgVGYgMCBnICkvRlQvVHgvRFI8PC9Gb250PDwvSGVsdiAxMCAwIFI+Pj4+L1JlY3RbMCAwIDAgMF0vQVA8PC9OIDM3IDAgUj4+L0ZmIDA+PgplbmRvYmoKNjUgMCBvYmoKPDwvQlM8PC9TL1MvVyAxPj4vU3VidHlwZS9XaWRnZXQvVChIdW5kX1Jhc3NlKS9UeXBlL0Fubm90L1YoU2No5GZlcmh1bmQpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAzOCAwIFI+Pi9GZiAwPj4KZW5kb2JqCjY2IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoSHVuZF9HZXNjaGxlY2h0KS9UeXBlL0Fubm90L1Yod2VpYmxpY2gpL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiAzOSAwIFI+Pi9GZiAwPj4KZW5kb2JqCjY3IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoS2FzdHJhdGlvbikvVHlwZS9Bbm5vdC9WKG5laW4pL0YgNi9EQSgvSGVsdiAwIFRmIDAgZyApL0ZUL1R4L0RSPDwvRm9udDw8L0hlbHYgMTAgMCBSPj4+Pi9SZWN0WzAgMCAwIDBdL0FQPDwvTiA0MCAwIFI+Pi9GZiAwPj4KZW5kb2JqCjY4IDAgb2JqCjw8L0JTPDwvUy9TL1cgMT4+L1N1YnR5cGUvV2lkZ2V0L1QoSHVuZF9HZWJ1cnRkYXR1bSkvVHlwZS9Bbm5vdC9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gNDEgMCBSPj4vRmYgMD4+CmVuZG9iago2OSAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKEh1bmRfQWx0ZXIpL1R5cGUvQW5ub3QvVig1KS9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gNDIgMCBSPj4vRmYgMD4+CmVuZG9iago3MCAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKEh1bmRfQ2hpcE5yKS9UeXBlL0Fubm90L1YoMTIzNDU2Nzg5MTIzNDU2KS9GIDYvREEoL0hlbHYgMCBUZiAwIGcgKS9GVC9UeC9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4vUmVjdFswIDAgMCAwXS9BUDw8L04gNDMgMCBSPj4vRmYgMD4+CmVuZG9iago3MSAwIG9iago8PC9CUzw8L1MvUy9XIDE+Pi9TdWJ0eXBlL1dpZGdldC9UKEh1bmRfRmVsbGZhcmJlKS9U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ZWxkc1s0NyAwIFIgNDggMCBSIDQ5IDAgUiA1MCAwIFIgNTEgMCBSIDUyIDAgUiA1MyAwIFIgNTQgMCBSIDU1IDAgUiA1NiAwIFIgNTcgMCBSIDU4IDAgUiA1OSAwIFIgNjAgMCBSIDYxIDAgUiA2MiAwIFIgNjMgMCBSIDY0IDAgUiA2NSAwIFIgNjYgMCBSIDY3IDAgUiA2OCAwIFIgNjkgMCBSIDcwIDAgUiA3MSAwIFIgNzIgMCBSIDczIDAgUl0vREEoL0hlbHYgMCBUZiAwIGcgKS9EUjw8L0ZvbnQ8PC9IZWx2IDEwIDAgUj4+Pj4+PgplbmRvYmoKODMgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL0Fjcm9Gb3JtIDgyIDAgUi9QYWdlcyA3NSAwIFI+PgplbmRvYmoKeHJlZgowIDg0CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAyODA5IDAwMDAwIG4gCjAwMDAwMDQyMDYgMDAwMDAgbiAKMDAwMDAwNTYwNCAwMDAwMCBuIAowMDAwMDA1OTA5IDAwMDAwIG4gCjAwMDAwMDU5ODUgMDAwMDAgbiAKMDAwMDAwNjEyNSAwMDAwMCBuIAowMDAwMDA3NDA2IDAwMDAwIG4gCjAwMDAwMDYzNDEgMDAwMDAgbiAKMDAwMDAwNjU5NSAwMDAwMCBuIAowMDAwMDA2Njg0IDAwMDAwIG4gCjAwMDAwMDY5MzkgMDAwMDAgbiAKMDAwMDAzODI3NyAwMDAwMCBuIAowMDAwMDM4ODA0IDAwMDAwIG4gCjAwMDAwMDc1MzYgMDAwMDAgbiAKMDAwMDAwNzc5NCAwMDAwMCBuIAowMDAwMDA4MDUyIDAwMDAwIG4gCjAwMDAwMDgyNDcgMDAwMDAgbiAKMDAwMDAwODQ0MiAwMDAwMCBuIAowMDAwMDA4Njk1IDAwMDAwIG4gCjAwMDAwMDg5NTEgMDAwMDAgbiAKMDAwMDAwOTIwNiAwMDAwMCBuIAowMDAwMDA5NDAxIDAwMDAwIG4gCjAwMDAwMDk2NjQgMDAwMDAgbiAKMDAwMDAwOTg1OSAwMDAwMCBuIAowMDAwMDEwMDU0IDAwMDAwIG4gCjAwMDAwMTAzMzMgMDAwMDAgbiAKMDAwMDAxMDUyOCAwMDAwMCBuIAowMDAwMDEwODA3IDAwMDAwIG4gCjAwMDAwMTEwOTQgMDAwMDAgbiAKMDAwMDAxMTI3OCAwMDAwMCBuIAowMDAwMDExNDYzIDAwMDAwIG4gCjAwMDAwMTE2NDcgMDAwMDAgbiAKMDAwMDAxMTgzMiAwMDAwMCBuIAowMDAwMDEyMDE2IDAwMDAwIG4gCjAwMDAwMTIzMDMgMDAwMDAgbiAKMDAwMDAxMjQ4NyAwMDAwMCBuIAowMDAwMDEyNzQzIDAwMDAwIG4gCjAwMDAwMTMwMDYgMDAwMDAgbiAKMDAwMDAxMzI2NSAwMDAwMCBuIAowMDAwMDEzNTIwIDAwMDAwIG4gCjAwMDAwMTM3MTUgMDAwMDAgbiAKMDAwMDAxMzk2NyAwMDAwMCBuIAowMDAwMDE0MjI5IDAwMDAwIG4gCjAwMDAwMTQ0ODQgMDAwMDAgbiAKMDAwMDAxNDczNyAwMDAwMCBuIAowMDAwMDE0OTkwIDAwMDAwIG4gCjAwMDAwMTUxNjYgMDAwMDAgbiAKMDAwMDAxNTM1OCAwMDAwMCBuIAowMDAwMDE1ODQ0IDAwMDAwIG4gCjAwMDAwMTYwMjQgMDAwMDAgbiAKMDAwMDAxNjIwMSAwMDAwMCBuIAowMDAwMDE2MzcwIDAwMDAwIG4gCjAwMDAwMTY1NTYgMDAwMDAgbiAKMDAwMDAxNjcyNiAwMDAwMCBuIAowMDAwMDE2OTAwIDAwMDAwIG4gCjAwMDAwMTcwNzMgMDAwMDAgbiAKMDAwMDAxNzI0MiAwMDAwMCBuIAowMDAwMDE3NDI2IDAwMDAwIG4gCjAwMDAwMTc1OTggMDAwMDAgbiAKMDAwMDAxNzc2NyAwMDAwMCBuIAowMDAwMDE3OTY2IDAwMDAwIG4gCjAwMDAwMTgxMzEgMDAwMDAgbiAKMDAwMDAxODMzOSAwMDAwMCBuIAowMDAwMDE4NTE2IDAwMDAwIG4gCjAwMDAwMTg3MDAgMDAwMDAgbiAKMDAwMDAxODg4NiAwMDAwMCBuIAowMDAwMDE5MDYzIDAwMDAwIG4gCjAwMDAwMTkyMzggMDAwMDAgbiAKMDAwMDAxOTQxMiAwMDAwMCBuIAowMDAwMDE5NjAxIDAwMDAwIG4gCjAwMDAwMTk3ODIgMDAwMDAgbiAKMDAwMDAxOTk1OSAwMDAwMCBuIAowMDAwMDIwMTM2IDAwMDAwIG4gCjAwMDAwMjE0MTUgMDAwMDAgbiAKMDAwMDAyMTQ3NSAwMDAwMCBuIAowMDAwMDIzNjMzIDAwMDAwIG4gCjAwMDAwMjE5NTggMDAwMDAgbiAKMDAwMDAyMjA1MiAwMDAwMCBuIAowMDAwMDIzNzkwIDAwMDAwIG4gCjAwMDAwMzgwOTMgMDAwMDAgbiAKMDAwMDAzOTQ0OCAwMDAwMCBuIAowMDAwMDM5NzE0IDAwMDAwIG4gCnRyYWlsZXIKPDwvSW5mbyA0IDAgUi9JRCBbPGVlZWQ2YmEzM2YwZDY5ZjkzZWEyYzZjNWFhM2U0ZWJjPjw4ZGIwNDk0YjcxMmY5ZTE5NTJmZGMwMjI2Mjg3NzdhZj5dL1Jvb3QgODMgMCBSL1NpemUgODQ+PgolaVRleHQtNS41LjUKc3RhcnR4cmVmCjM5Nzc3CiUlRU9GCg=="; private static final byte[] PDF_DECODED = Base64.getDecoder().decode(PDF_ENCODED.getBytes()); - +//TODO aus Datei laden private static final String XML_CONTENT = """ <?xml version="1.0" encoding="UTF-8"?> <myForm xmlns:pdf="http://xmlns.cit.de/assistants/pdf" @@ -98,12 +98,12 @@ public class AttachmentsTestFactory { createAttachments(List.of( createFile(FILE_NAME_ZIP_ATTACHMENT, ZIP_ENCRYPTED_DECODED, ZIP_CONTENT_TYPE)), FILE_GROUP_ZIP_NAME)); - public static final Map<String, Object> FORMDATA_WITH_AFM_FILES = Map.of(MAPPED_FILES, + public static final Map<String, Object> FORMDATA_WITH_AFM_FILES = Map.of(FIELD_NAME_MAPPED_FILES, Map.of( ATTACHMENTS, AFM_ATTACHMMENTS, REPRESENTATIONS, AFM_REPRESENTATIONS)); - public static final Map<String, Object> FORMDATA_WITH_NO_ATTACHMENTS = Map.of(MAPPED_FILES, + public static final Map<String, Object> FORMDATA_WITH_NO_ATTACHMENTS = Map.of(FIELD_NAME_MAPPED_FILES, Map.of( ATTACHMENTS, List.of(), REPRESENTATIONS, FORMSOLUTIONS_REPRESENTATIONS)); diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapperTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapperTest.java index be8ea56a6e04d0a41c14057aff40c4514355071a..079da0827d5013e789cdacabb7dc43f0ffe011c8 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapperTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerMapperTest.java @@ -24,44 +24,88 @@ package de.itvsh.kop.eingangsadapter.semantik.enginebased; import static de.itvsh.kop.eingangsadapter.common.formdata.AntragstellerTestFactory.*; -import static de.itvsh.kop.eingangsadapter.semantik.enginebased.FormSolutionsAntragstellerMapper.*; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Spy; + +import de.itvsh.kop.eingangsadapter.common.formdata.Antragsteller; +import de.itvsh.kop.eingangsadapter.common.formdata.FormData; class FormSolutionsAntragstellerMapperTest { - private FormSolutionsAntragstellerMapper mapper = new FormSolutionsAntragstellerMapper(); + @Spy + private final FormSolutionsAntragstellerMapper mapper = new FormSolutionsAntragstellerMapper(); + + @DisplayName("Parse formData") @Nested - class TestAntragstellerMapping { + class TestParseFormData { + + private final FormData formData = FormSolutionsAntragstellerTestFactory.create(); + @Test - void shouldParsePostfachId() { - var formData = mapper.parseFormData(FormSolutionsAntragstellerTestFactory.create()); + void shouldCallBuildAntragsteller() { + parseFormData(); - assertThat(formData.getAntragsteller().getPostfachId()) - .isEqualTo(POSTFACH_ID); + verify(mapper).buildAntragsteller(formData); } @Test - void shouldParseVorname() { - var formData = mapper.parseFormData(FormSolutionsAntragstellerTestFactory.create()); + void shouldCallRemoveProcessedData() { + parseFormData(); - assertThat(formData.getAntragsteller().getVorname()).isEqualTo(VORNAME); + verify(mapper).buildAntragsteller(formData); } @Test - void shouldParseNachname() { - var formData = mapper.parseFormData(FormSolutionsAntragstellerTestFactory.create()); + void shouldReturnValue() { + var result = parseFormData(); - assertThat(formData.getAntragsteller().getNachname()).isEqualTo(NACHNAME); + assertThat(result).usingRecursiveComparison().ignoringFields("antragsteller", "formData").isEqualTo(formData); } @Test - void shouldRemovedParsedPostfachId() { - var formData = mapper.parseFormData(FormSolutionsAntragstellerTestFactory.create()); + void shouldRemovePostkorbhandle() { + var result = parseFormData(); + + assertThat(result.getFormData()).doesNotContainKey(FormSolutionsAntragstellerMapper.POSTKORBHANDLE); + } + + private FormData parseFormData() { + return mapper.parseFormData(formData); + } + + @DisplayName("build antragsteller") + @Nested + class TestBuildAntragsteller { + + @Test + void shouldHavePostfachId() { + var antragsteller = buildAntragsteller(); + + assertThat(antragsteller.getPostfachId()).isEqualTo(POSTFACH_ID); + } + + @Test + void shouldHaveVorname() { + var antragsteller = buildAntragsteller(); + + assertThat(antragsteller.getVorname()).isEqualTo(VORNAME); + } + + @Test + void shouldHaveNachname() { + var antragsteller = buildAntragsteller(); + + assertThat(antragsteller.getNachname()).isEqualTo(NACHNAME); + } - assertThat(formData.getFormData().get(POSTKORBHANDLE)).isNull(); + private Antragsteller buildAntragsteller() { + return mapper.buildAntragsteller(formData); + } } } -} +} \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerTestFactory.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerTestFactory.java index 97722d19dc0d1d37fc36ae0d9d3baaac2faa04e4..a1694d61e8e4e3296f5367a647e6f8b58179441a 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerTestFactory.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsAntragstellerTestFactory.java @@ -34,23 +34,30 @@ import java.util.Map; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; class FormSolutionsAntragstellerTestFactory { - static final String ANTRAGSTELLER_NAME_PANEL_IDENTIFIER = "AS_Name1"; - static final List<Map<String, Object>> ANTRAGSTELLER_PANEL_CONTENT = List.of( - Map.of(IDENTIFIER, ANTRAGSTELLER_NAME_PANEL_IDENTIFIER), - Map.of(COMPONENTS, List.of( - Map.of(IDENTIFIER, VORNAME_KEY, STRING_VALUE, VORNAME), - Map.of(IDENTIFIER, NACHNAME_KEY, STRING_VALUE, NACHNAME)))); - static final List<Map<String, Object>> PANELS_CONTENT = List.of( - Map.of(IDENTIFIER, ANTRAGSTELLER_PANEL_IDENTIFIER), - Map.of(COMPONENTS, ANTRAGSTELLER_PANEL_CONTENT)); - static final Map<String, Object> ANTRAGSTELLER_DATA = Map.of(PANELS, PANELS_CONTENT); + static final String ANTRAGSTELLER_NAME_PANEL_IDENTIFIER = "AS_Name1"; public static FormData create() { return createBuilder().build(); } public static FormData.FormDataBuilder createBuilder() { - return FormData.builder().formData(Map.of(FormSolutionsAntragstellerMapper.POSTKORBHANDLE, POSTFACH_ID, ASSISTANT, ANTRAGSTELLER_DATA)); + return FormData.builder().formData(Map.of( + FormSolutionsAntragstellerMapper.POSTKORBHANDLE, POSTFACH_ID, + ASSISTANT, createAssistantMap())); + } + + private static Map<String, Object> createAssistantMap() { + return Map.of(PANELS, List.of( + Map.of(IDENTIFIER, ANTRAGSTELLER_PANEL_IDENTIFIER), + Map.of(COMPONENTS, createAntragstellerPanelContentList()))); + } + + private static List<Map<String, Object>> createAntragstellerPanelContentList() { + return List.of( + Map.of(IDENTIFIER, ANTRAGSTELLER_NAME_PANEL_IDENTIFIER), + Map.of(COMPONENTS, List.of( + Map.of(IDENTIFIER, VORNAME_KEY, STRING_VALUE, VORNAME), + Map.of(IDENTIFIER, NACHNAME_KEY, STRING_VALUE, NACHNAME)))); } -} +} \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterITCase.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterITCase.java index 5bb1c23a2fee52f8ca777bd24b7fbc8e65ea7d02..b9f35ee877eedc513bda8ddd90275fbc7778c87f 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterITCase.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterITCase.java @@ -262,7 +262,7 @@ public class FormSolutionsEngineBasedAdapterITCase { createFile(FILE_NAME_ZIP_ATTACHMENT, ZIP_DECODED, ZIP_CONTENT_TYPE)), FILE_GROUP_ZIP_NAME); Map<String, Object> plainMap = getTestDataFromFile(); - plainMap.put(MAPPED_FILES, Map.of( + plainMap.put(FIELD_NAME_MAPPED_FILES, Map.of( ATTACHMENTS, formsolutionsAttachments, REPRESENTATIONS, FORMSOLUTIONS_REPRESENTATIONS)); return FormData.builder().formData(plainMap).build(); diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTest.java index db0d59b2443f171bceb2725a802bc38b02947914..57251ef748719cacfc59dd2ae5ac9c0a23e55e82 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTest.java @@ -29,62 +29,88 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.Collections; -import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.springframework.test.util.ReflectionTestUtils; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; class FormSolutionsEngineBasedAdapterTest { + @Spy @InjectMocks private FormSolutionsEngineBasedAdapter adapter; @Mock private FormSolutionsEngineBasedMapper mapper; - private FormData formData = FormSolutionsEngineBasedAdapterTestFactory.createIncommingDataBuilder().build(); - - @BeforeEach - void mockMapper() { - when(mapper.parseFormData(any())).thenReturn(formData.toBuilder().formData(new HashMap<String, Object>()).build()); - var mappers = Collections.singletonList(mapper); - ReflectionTestUtils.setField(adapter, "mappers", mappers); - } - + @DisplayName("Parse formData") @Nested class TestParseFormData { + private final FormData formData = FormSolutionsEngineBasedAdapterTestFactory.create(); + + @BeforeEach + void mockMappers() { + ReflectionTestUtils.setField(adapter, "mappers", Collections.singletonList(mapper)); + } + @Test void shouldCallMappers() { + when(mapper.parseFormData(any())).thenReturn(formData); + adapter.parseFormData(formData); verify(mapper).parseFormData(formData); } - } - - @Nested - class TestRemove { @Test - void shouldRemoveRoot() { - var parsed = adapter.parseFormData(formData); + void shouldCallRemoveProcessedRawData() { + when(mapper.parseFormData(any())).thenReturn(formData); - assertThat(parsed.getFormData().get(ASSISTANT)).isNull(); + adapter.parseFormData(formData); + verify(adapter).removeProcessedData(formData); } @Test - void shouldRemoveKnownUnmapped() { - var parsed = adapter.parseFormData(formData); + void shouldReturnValue() { + doReturn(formData).when(adapter).removeProcessedData(any()); + + var result = adapter.parseFormData(formData); + + assertThat(result).isEqualTo(formData); + } + + @DisplayName("remove processed data") + @Nested + class TestRemoveProcessedData { + + @Test + void shouldRemoveAssistant() { + var cleanedFormData = adapter.removeProcessedData(formData); + + assertThat(cleanedFormData.getFormData()).doesNotContainKey(ASSISTANT); + } + + @Test + void shouldRemoveAnliegenId() { + var cleanedFormData = adapter.removeProcessedData(formData); + + assertThat(cleanedFormData.getFormData()).doesNotContainKey(ANLIEGEN_ID); + } - assertThat(parsed.getFormData().get(KOMMUNALVERWALTUNG_ID)).isNull(); - assertThat(parsed.getFormData().get(ANLIEGEN_ID)).isNull(); + @Test + void shouldRemoveKommunalVerwaltungId() { + var cleanedFormData = adapter.removeProcessedData(formData); + assertThat(cleanedFormData.getFormData()).doesNotContainKey(KOMMUNALVERWALTUNG_ID); + } } } } \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTestFactory.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTestFactory.java index c2cf7aea78993206b3fa5eff4056361f16aeb638..ea0e9dc201b0b7398c4b73009cafe3c8e4c98933 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTestFactory.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsEngineBasedAdapterTestFactory.java @@ -32,34 +32,38 @@ import de.itvsh.kop.eingangsadapter.common.formdata.FormData; import de.itvsh.kop.eingangsadapter.common.formdata.FormDataTestFactory; class FormSolutionsEngineBasedAdapterTestFactory { - public static final String ROOT = ASSISTANT; - public static final String ROOT_IDENTIFIER = IDENTIFIER; - public static final String ROOT_IDENTIFIER_VALUE = "root"; - public static final String PANELS = FormSolutionsPanelMapper.PANELS; - public static final String PANELS_IDENTIFIER = IDENTIFIER; - public static final String PANELS_IDENTIFIER_VALUE = "panels"; - public static final String COMPONENTS = FormSolutionsPanelMapper.COMPONENTS; - public static final String COMPONENTS_IDENTIFIER = IDENTIFIER; + public static final String ANLIEGEN_ID_VALUE = "1234"; public static final String KOMMUNALVERWALTUNG_ID_VALUE = "100000000"; + public static final String ASSISTANT_IDENTIFIER_VALUE = "root"; + public static final String PANELS_IDENTIFIER_VALUE = "panels"; + public static FormData create() { return createBuilder().build(); } public static FormData.FormDataBuilder createBuilder() { - return FormDataTestFactory.createBuilder(); + return FormDataTestFactory.createBuilder() + .formData(createFormDataMap()); + } + + private static Map<String, Object> createFormDataMap() { + return Map.of( + ASSISTANT, createAssistantMap(), + ANLIEGEN_ID, ANLIEGEN_ID_VALUE, + KOMMUNALVERWALTUNG_ID, KOMMUNALVERWALTUNG_ID_VALUE); + } + + private static Map<String, Object> createAssistantMap() { + return Map.of( + IDENTIFIER, ASSISTANT_IDENTIFIER_VALUE, + FormSolutionsPanelMapper.PANELS, List.of(createPanelMap())); } - public static FormData.FormDataBuilder createIncommingDataBuilder() { - return FormData.builder() - .formData(Map.of(ROOT, - Map.of( - ROOT_IDENTIFIER, ROOT_IDENTIFIER_VALUE, - PANELS, List.of(Map.of( - PANELS_IDENTIFIER, PANELS_IDENTIFIER_VALUE, - COMPONENTS, FormDataTestFactory.NESTED_LIST_WITH_OBJECTS))), - ANLIEGEN_ID, ANLIEGEN_ID_VALUE, - KOMMUNALVERWALTUNG_ID, KOMMUNALVERWALTUNG_ID_VALUE)); + private static Map<String, Object> createPanelMap() { + return Map.of( + IDENTIFIER, PANELS_IDENTIFIER_VALUE, + FormSolutionsPanelMapper.COMPONENTS, FormDataTestFactory.NESTED_LIST_WITH_OBJECTS); } } \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsFilesMapperTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsFilesMapperTest.java index 09f0f4587d9ae87b5b13cb947df4ec0454d77cb3..4686f8d329f78055e89514cbd47b4d40cb80999b 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsFilesMapperTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsFilesMapperTest.java @@ -60,7 +60,7 @@ class FormSolutionsFilesMapperTest { IncomingFileTestFactory.create())) .build()); - private final FormData formData = AttachmentsTestFactory.createBuilder().formData(Map.of(MAPPED_FILES, + private final FormData formData = AttachmentsTestFactory.createBuilder().formData(Map.of(FIELD_NAME_MAPPED_FILES, Map.of( ATTACHMENTS, attachments, REPRESENTATIONS, FORMSOLUTIONS_REPRESENTATIONS))) @@ -123,7 +123,7 @@ class FormSolutionsFilesMapperTest { @Nested class TestEncryptedAttachments { - private final FormData formData = FormData.builder().formData(Map.of(MAPPED_FILES, FORMDATA_WITH_FORMSOLUTIONS_ATTACHMMENTS_ENCRYPTED)) + private final FormData formData = FormData.builder().formData(Map.of(FIELD_NAME_MAPPED_FILES, FORMDATA_WITH_FORMSOLUTIONS_ATTACHMMENTS_ENCRYPTED)) .build(); @Test diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapperTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapperTest.java index 902a3047a4f3ed8c0d19c7179f88cde66aa82b04..dc4bcd9b4d6abb5199a2038d6514f52d6fdeb219 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapperTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderMapperTest.java @@ -25,41 +25,99 @@ package de.itvsh.kop.eingangsadapter.semantik.enginebased; import static de.itvsh.kop.eingangsadapter.semantik.enginebased.FormSolutionsHeaderTestFactory.*; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Spy; + +import de.itvsh.kop.eingangsadapter.common.formdata.FormData; +import de.itvsh.kop.eingangsadapter.common.formdata.FormHeader; class FormSolutionsHeaderMapperTest { - private FormSolutionsHeaderMapper mapper = new FormSolutionsHeaderMapper(); + @Spy + private final FormSolutionsHeaderMapper mapper = new FormSolutionsHeaderMapper(); + + @DisplayName("Parse formData") @Nested - class TestHeaderMapping { + class TestParseFormData { + + private final FormData formData = FormSolutionsHeaderTestFactory.create(); + @Test - void shouldParseFormName() { - var formData = mapper.parseFormData(FormSolutionsHeaderTestFactory.create()); + void shouldCallBuildFormHeader() { + parseFormData(); - assertThat(formData.getHeader().getFormName()).isEqualTo(FORM_NAME); + verify(mapper).buildFormHeader(formData); } @Test - void shouldParseFormId() { - var formData = mapper.parseFormData(FormSolutionsHeaderTestFactory.create()); + void shouldReturnValue() { + var result = parseFormData(); - assertThat(formData.getHeader().getFormId()).isEqualTo(FORM_NAME); + assertThat(result).usingRecursiveComparison().ignoringFields("header", "formData").isEqualTo(formData); } @Test - void shouldParseTransactionId() { - var formData = mapper.parseFormData(FormSolutionsHeaderTestFactory.create()); + void shouldRemoveTransactionId() { + var result = parseFormData(); - assertThat(formData.getHeader().getRequestId()).isEqualTo(REQUEST_ID); + assertThat(result.getFormData()).doesNotContainKey(FormSolutionsHeaderMapper.TRANSACTION_ID); } - @Test - void shouldSetFormEngineName() { - var formData = mapper.parseFormData(FormSolutionsHeaderTestFactory.create()); + private FormData parseFormData() { + return mapper.parseFormData(formData); + } + + @DisplayName("build form header") + @Nested + class TestBuildFormHeader { + + @Test + void shouldHaveFormName() { + var formHeader = buildFormHeader(); + + assertThat(formHeader.getFormName()).isEqualTo(FORM_NAME); + } + + @Test + void shouldHaveFormId() { + var formHeader = buildFormHeader(); + + assertThat(formHeader.getFormId()).isEqualTo(FORM_NAME); + } + + @Test + void shouldHaveTransactionId() { + var formHeader = buildFormHeader(); + + assertThat(formHeader.getRequestId()).isEqualTo(REQUEST_ID); + } + + @Test + void shouldHaveFormEngineName() { + var formHeader = buildFormHeader(); + + assertThat(formHeader.getFormEngineName()).isEqualTo(FormSolutionsHeaderMapper.FORM_ENGINE_NAME); + } + + private FormHeader buildFormHeader() { + return mapper.buildFormHeader(formData); + } + } + + @DisplayName("remove processed data") + @Nested + class TestRemoveProcessedData { + + @Test + void shouldRemoveTransactionId() { + var cleanedFormData = mapper.removeProcessedData(formData); - assertThat(formData.getHeader().getFormEngineName()).isEqualTo(FormSolutionsHeaderMapper.FS_FORMENGINE_NAME); + assertThat(cleanedFormData).doesNotContainKey(FormSolutionsHeaderMapper.TRANSACTION_ID); + } } } -} +} \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderTestFactory.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderTestFactory.java index 96d256a4110b813f91bbd01fde41679517b494d7..b22177580dd5c398011e235847ec8059fb1d3ed5 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderTestFactory.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsHeaderTestFactory.java @@ -31,17 +31,18 @@ import java.util.Map; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; public class FormSolutionsHeaderTestFactory { + public static final String FORM_NAME = "form name"; public static final Object REQUEST_ID = "transaction id"; - public static final Map<String, Object> ASSISTANT_1 = Map.of(IDENTIFIER, FORM_NAME); public static FormData create() { return createBuilder().build(); } public static FormData.FormDataBuilder createBuilder() { - return FormData.builder().formData(Map.of( - ASSISTANT, ASSISTANT_1, - TRANSACTION_ID, REQUEST_ID)); + return FormData.builder() + .formData(Map.of( + ASSISTANT, Map.of(IDENTIFIER, FORM_NAME), + TRANSACTION_ID, REQUEST_ID)); } } diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapperTest.java index c181975029e9be60b9029f013ef8b200662086ef..e50be8e0e25aef603417720faaa88639739de73f 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleMapperTest.java @@ -26,28 +26,73 @@ package de.itvsh.kop.eingangsadapter.semantik.enginebased; import static de.itvsh.kop.eingangsadapter.common.formdata.ZustaendigsStelleTestFactory.*; import static de.itvsh.kop.eingangsadapter.semantik.enginebased.FormSolutionsZustaendigeStelleMapper.*; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Spy; + +import de.itvsh.kop.eingangsadapter.common.formdata.FormData; class FormSolutionsZustaendigeStelleMapperTest { - private FormSolutionsZustaendigeStelleMapper mapper = new FormSolutionsZustaendigeStelleMapper(); + @Spy + private final FormSolutionsZustaendigeStelleMapper mapper = new FormSolutionsZustaendigeStelleMapper(); + + @DisplayName("Parse formData") @Nested - class TestZustaendigeStelleMapping { + class TestParseFormData { + + private final FormData formData = FormSolutionsZustaendigeStelleTestFactory.create(); + @Test - void shouldParseOrgansisationeinheitenId() { - var formData = mapper.parseFormData(FormSolutionsZustaendigeStelleTestFactory.create()); + void shouldCallBuildZustaendigeStelle() { + parseFormData(); - assertThat(formData.getZustaendigeStelle().getOrganisationseinheitenId()) - .isEqualTo(ORGANISATIONSEINHEIT_ID); + verify(mapper).buildZustaendigeStelle(formData); } @Test - void shouldRemove() { - var formData = mapper.parseFormData(FormSolutionsZustaendigeStelleTestFactory.create()); + void shouldCallRemoveProcessedData() { + parseFormData(); + + verify(mapper).removeProcessedData(formData); + } + + @Test + void shouldReturnValue() { + var result = parseFormData(); + + assertThat(result).usingRecursiveComparison().ignoringFields("zustaendigeStelle", "formData").isEqualTo(formData); + } + + private FormData parseFormData() { + return mapper.parseFormData(formData); + } + + @DisplayName("build zustaendigeStelle") + @Nested + class TestBuildZustaendigeStelle { + + @Test + void shouldHaveOrganisationseinheitenId() { + var zustaendigeStelle = mapper.buildZustaendigeStelle(formData); + + assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEqualTo(ORGANISATIONSEINHEIT_ID); + } + } + + @DisplayName("remove processed data") + @Nested + class TestRemoveProcessedData { + + @Test + void shouldRemoveZustaendigeStelle() { + var cleanedFormData = mapper.removeProcessedData(formData); - assertThat(formData.getFormData().get(ZUSTAENDIGE_STELLE)).isNull(); + assertThat(cleanedFormData).doesNotContainKey(ZUSTAENDIGE_STELLE); + } } } -} +} \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleTestFactory.java b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleTestFactory.java index 222a2369f5e26ed6c2365d3168b4e3d73b4ed5da..0bc3d1f0218a61a481160821cb6d1b91f5691a53 100644 --- a/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleTestFactory.java +++ b/semantik-adapter/src/test/java/de/itvsh/kop/eingangsadapter/semantik/enginebased/FormSolutionsZustaendigeStelleTestFactory.java @@ -30,12 +30,13 @@ import java.util.Map; import de.itvsh.kop.eingangsadapter.common.formdata.FormData; public class FormSolutionsZustaendigeStelleTestFactory { + public static FormData create() { return createBuilder().build(); } public static FormData.FormDataBuilder createBuilder() { - return FormData.builder().formData(Map.of(FormSolutionsZustaendigeStelleMapper.ZUSTAENDIGE_STELLE, ORGANISATIONSEINHEIT_ID)); + return FormData.builder() + .formData(Map.of(FormSolutionsZustaendigeStelleMapper.ZUSTAENDIGE_STELLE, ORGANISATIONSEINHEIT_ID)); } - -} +} \ No newline at end of file