diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java b/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java index cfbade2e911eaf2398d9e206a20a57ef79bf77f9..2ed5f8cb707922f99dd1557a9276ccb7f7d36b5f 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java @@ -4,6 +4,8 @@ import static java.util.Collections.*; import java.io.IOException; import java.io.InputStream; +import java.util.List; +import java.util.Set; import javax.xml.parsers.DocumentBuilder; @@ -33,13 +35,13 @@ public class XdomeaXtaMessageCreator { public XtaMessage createMessage(XtaFile xdomeaZipFile) throws ClientException { return XtaMessage.builder() - .metaData(deriveMetaData(xdomeaZipFile)) + .metaData(deriveValidMetaData(xdomeaZipFile)) .messageFile(xdomeaZipFile) .attachmentFiles(emptyList()) .build(); } - XtaMessageMetaData deriveMetaData(XtaFile xdomeaZipFile) throws ClientException { + XtaMessageMetaData deriveValidMetaData(XtaFile xdomeaZipFile) throws ClientException { try { var xdomeaXmlValues = readXdomeaXmlValues(xdomeaZipFile); var messageMetadataData = metadataMapper.mapXtaMessageMetadata(xdomeaXmlValues); @@ -48,9 +50,19 @@ public class XdomeaXtaMessageCreator { xdomeaXmlValues.processId(), messageMetadataData.messageTypeCode() ); + validatePrimaryDocumentReferences(xdomeaZipFile, xdomeaXmlValues.primaryDocumentNames()); return messageMetadataData; } catch (TechnicalException e) { - throw new ClientException("Failed to derive message metadata from xdomea document!", e); + throw new ClientException("Failed to derive valid message metadata from xdomea document!", e); + } + } + + void validatePrimaryDocumentReferences(XtaFile xdomeaZipFile, List<String> primaryDocumentNames) throws ClientException { + var entryNames = Set.copyOf(zipFileEntryReader.getEntryNames(xdomeaZipFile.content())); + for (var primaryDocumentName : primaryDocumentNames) { + if (!entryNames.contains(primaryDocumentName)) { + throw new ClientException("Primary document reference '%s' not found in xdomea zip file!".formatted(primaryDocumentName)); + } } } diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java index df4cff99ead99f19b2b6b3ae70fb413674245ef3..45adea934b21aeec30fdb28f5055ed2887f0ddac 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java @@ -1,6 +1,7 @@ package de.ozgcloud.xta.client.xdomea.reader; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -14,16 +15,16 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class XdomeaValueReader { - static final String PROCESS_ID_XPATH = getTextXpath("Kopf", "ProzessID"); - static final String AUTHOR_ID_SUFFIX_XPATH = getTextXpath("Kopf", "Absender", "code"); - static final String READER_ID_SUFFIX_XPATH = getTextXpath("Kopf", "Empfaenger", "code"); - static final String MESSAGE_TYPE_ID_SUFFIX_XPATH = getTextXpath("Kopf", "Nachrichtentyp", "code"); + static final String PROCESS_ID_XPATH = getXpath("Kopf", "ProzessID"); + static final String AUTHOR_ID_SUFFIX_XPATH = getXpath("Kopf", "Absender", "code"); + static final String READER_ID_SUFFIX_XPATH = getXpath("Kopf", "Empfaenger", "code"); + static final String MESSAGE_TYPE_ID_SUFFIX_XPATH = getXpath("Kopf", "Nachrichtentyp", "code"); + static final String PRIMARY_DOCUMENT_NAME_XPATH = getXpath("Primaerdokument", "Dateiname"); - static String getTextXpath(String... hierarchy) { + static String getXpath(String... hierarchy) { return Arrays.stream(hierarchy) .map(h -> "//*[local-name() = '" + h + "']") - .collect(Collectors.joining()) - + "/text()"; + .collect(Collectors.joining()); } private final Map<String, XmlValueReader> xmlValueReaders; @@ -34,12 +35,20 @@ public class XdomeaValueReader { .messageTypeCode(readRequiredValue(xdomeaXmlDocument, MESSAGE_TYPE_ID_SUFFIX_XPATH)) .authorIdSuffix(readRequiredValue(xdomeaXmlDocument, AUTHOR_ID_SUFFIX_XPATH)) .readerIdSuffix(readRequiredValue(xdomeaXmlDocument, READER_ID_SUFFIX_XPATH)) + .primaryDocumentNames(readPrimaryDocumentNames(xdomeaXmlDocument)) .build(); } + List<String> readPrimaryDocumentNames(Document xdomeaXmlDocument) { + return getXmlValueReader(PRIMARY_DOCUMENT_NAME_XPATH) + .readNonEmptyTexts(xdomeaXmlDocument) + .toList(); + } + String readRequiredValue(Document xdomeaXmlDocument, String xpathString) throws ClientException { return getXmlValueReader(xpathString) - .readString(xdomeaXmlDocument) + .readNonEmptyTexts(xdomeaXmlDocument) + .findFirst() .orElseThrow(() -> new ClientException("Required value " + xpathString + " not found in xdomea xml document!")); } diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java index 569488d2f3d6cbb673657b8ed309d16af1c173bc..9dbcf5e1c3b6d317870ffd93e4c062bea1976af7 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java @@ -33,7 +33,8 @@ public class XdomeaValueReaderFactory { PROCESS_ID_XPATH, MESSAGE_TYPE_ID_SUFFIX_XPATH, AUTHOR_ID_SUFFIX_XPATH, - READER_ID_SUFFIX_XPATH + READER_ID_SUFFIX_XPATH, + PRIMARY_DOCUMENT_NAME_XPATH ).collect(Collectors.toMap( xpath -> xpath, this::createXmlValueReader diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java index 8f7ce947440a879d0761f87abefd1ba9a64ea85e..7783474d380204b3ea6b9c9d168db9c847440318 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java @@ -1,5 +1,8 @@ package de.ozgcloud.xta.client.xdomea.reader; +import java.util.List; + +import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import lombok.Builder; @@ -9,6 +12,7 @@ public record XdomeaXmlValues( @NotBlank String processId, @NotBlank String messageTypeCode, @NotBlank String authorIdSuffix, - @NotBlank String readerIdSuffix + @NotBlank String readerIdSuffix, + @Valid List<@NotBlank String> primaryDocumentNames ) { } diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReader.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReader.java index 094ae50eabdf1dc9aad81e76bf2c09d051fa25a5..642bff51e49b4c7ff2b3c2d8f7cbefc362dc4b67 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReader.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReader.java @@ -1,12 +1,15 @@ package de.ozgcloud.xta.client.xdomea.reader; -import java.util.Optional; +import java.util.stream.IntStream; +import java.util.stream.Stream; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import de.ozgcloud.common.errorhandling.TechnicalException; import lombok.Builder; @@ -16,24 +19,34 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class XmlValueReader { - private final XPathExpression textXpath; + private final XPathExpression xPathExpression; - public Optional<String> readString(Document xmlDocument) { - return findStringByTextXpath(xmlDocument, textXpath) - .map(String::trim) - .filter(s -> !s.isBlank()); + public Stream<String> readNonEmptyTexts(Document xmlDocument) { + return getTextsFromNodes(queryNodeList(xmlDocument, xPathExpression)) + .filter(s -> !s.isEmpty()); } - private Optional<String> findStringByTextXpath(Document xdomeaXmlDocument, XPathExpression textXpath) { + private NodeList queryNodeList(Document xmlDocument, XPathExpression xPathExpression) { try { - return Optional.ofNullable((String) textXpath + return (NodeList) xPathExpression .evaluate( - xdomeaXmlDocument.getDocumentElement(), - XPathConstants.STRING - )); + xmlDocument.getDocumentElement(), + XPathConstants.NODESET + ); } catch (XPathExpressionException e) { throw new TechnicalException("Failed to execute xpath search!", e); } } + private Stream<String> getTextsFromNodes(NodeList nodeList) { + return streamNodeList(nodeList) + .map(Node::getTextContent) + .map(String::trim); + } + + private Stream<Node> streamNodeList(NodeList nodeList) { + return IntStream.range(0, nodeList.getLength()) + .mapToObj(nodeList::item); + } + } diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactory.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactory.java index 90966ec68d9e684e225bfe02aee739b51fba0659..5f28091a231a036a4dfefd2b6e9a08883199e0c4 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactory.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactory.java @@ -25,7 +25,7 @@ public class XmlValueReaderFactory { public XmlValueReader create() { return XmlValueReader.builder() - .textXpath(compileXPathExpression()) + .xPathExpression(compileXPathExpression()) .build(); } } diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReader.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReader.java index 2164cb8d8c5d05833e87325984876a2e22d45f37..8b0df0b9cc40098cd285e228fed1895c0a66e862 100644 --- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReader.java +++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReader.java @@ -2,6 +2,8 @@ package de.ozgcloud.xta.client.xdomea.reader; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import java.util.function.Function; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -30,4 +32,18 @@ public class ZipFileEntryReader { throw new TechnicalException("Failed reading zip file!", e); } } + + public List<String> getEntryNames(DataHandler zipFileContent) { + var entryNames = new ArrayList<String>(); + try (var zipInputStream = new ZipInputStream(zipFileContent.getInputStream())) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + entryNames.add(entry.getName()); + zipInputStream.closeEntry(); + } + return entryNames; + } catch (IOException e) { + throw new TechnicalException("Failed reading zip file!", e); + } + } } diff --git a/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java b/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java index 2c62293e5ce016249122a58d4845e6b13ac4482f..ca099c7446385e4efee53a903dd6b922e2cd6fe7 100644 --- a/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java +++ b/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java @@ -1,5 +1,7 @@ package de.ozgcloud.xta.client.factory; +import java.util.List; + import de.ozgcloud.xta.client.xdomea.reader.XdomeaXmlValues; public class XdomeaXmlValuesTestFactory { @@ -9,6 +11,8 @@ public class XdomeaXmlValuesTestFactory { public static final String AUTHOR_ID_SUFFIX = "authorIdSuffix"; public static final String READER_ID_SUFFIX = "readerIdSuffix"; + public static final List<String> PRIMARY_DOCUMENT_NAMES = List.of("doc.pdf", "doc.xml"); + public static XdomeaXmlValues create() { return createBuilder().build(); } @@ -18,6 +22,7 @@ public class XdomeaXmlValuesTestFactory { .processId(PROCESS_ID) .messageTypeCode(SHORT_MESSAGE_TYPE_CODE) .authorIdSuffix(AUTHOR_ID_SUFFIX) - .readerIdSuffix(READER_ID_SUFFIX); + .readerIdSuffix(READER_ID_SUFFIX) + .primaryDocumentNames(PRIMARY_DOCUMENT_NAMES); } } diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorITCase.java b/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorITCase.java index 4859c4cda6c4cdb80157f882c6fc817ea70e3fa2..b508b5322ee0c21a7b3d9dfb8077399e6259f3bb 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorITCase.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorITCase.java @@ -106,12 +106,12 @@ class XdomeaXtaMessageCreatorITCase { } @DisplayName("should throw client exception for invalid message 0401") - @Test - @SneakyThrows - void shouldThrowClientExceptionForInvalidMessage0401() { + @ParameterizedTest + @ValueSource(strings = { "invalid-ProzessID.patch", "invalid-reference-to-primary-document.patch" }) + void shouldThrowClientExceptionForInvalidMessage0401(String patchName) { var invalidMessageZipFile = loadMessageFileWithPatch( "abgabe0401-kleiner-waffenschein", - "invalid-ProzessID.patch" + patchName ); assertThatThrownBy(() -> creator.createMessage(invalidMessageZipFile)) diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java index 0155421cdcf5b27527a87d57eb41777646035790..134454daa3c437f6180b664e6b416598ee8ce594 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.io.InputStream; +import java.util.List; import java.util.function.Function; import javax.xml.parsers.DocumentBuilder; @@ -69,7 +70,7 @@ class XdomeaXtaMessageCreatorTest { @BeforeEach @SneakyThrows void mock() { - doReturn(metaData).when(creator).deriveMetaData(xdomeaZipFile); + doReturn(metaData).when(creator).deriveValidMetaData(xdomeaZipFile); } @DisplayName("should return metadata") @@ -102,9 +103,9 @@ class XdomeaXtaMessageCreatorTest { } } - @DisplayName("derive meta data") + @DisplayName("derive valid meta data") @Nested - class TestDeriveMetaData { + class TestDeriveValidMetaData { private XtaFile xdomeaZipFile; @@ -130,7 +131,7 @@ class XdomeaXtaMessageCreatorTest { void shouldReturn() { mockValidMetadata(); - var result = creator.deriveMetaData(xdomeaZipFile); + var result = creator.deriveValidMetaData(xdomeaZipFile); assertThat(result).isEqualTo(metaData); } @@ -141,7 +142,7 @@ class XdomeaXtaMessageCreatorTest { void shouldVerifyZipFileName() { mockValidMetadata(); - creator.deriveMetaData(xdomeaZipFile); + creator.deriveValidMetaData(xdomeaZipFile); verify(creator).validateZipFileName( XTA_FILE_NAME, @@ -150,14 +151,25 @@ class XdomeaXtaMessageCreatorTest { ); } + @DisplayName("should verify primary document references") + @Test + @SneakyThrows + void shouldVerifyPrimaryDocumentReferences() { + mockValidMetadata(); + + creator.deriveValidMetaData(xdomeaZipFile); + + verify(creator).validatePrimaryDocumentReferences( + xdomeaZipFile, + PRIMARY_DOCUMENT_NAMES + ); + } + @SneakyThrows private void mockValidMetadata() { doReturn(metaData).when(metadataMapper).mapXtaMessageMetadata(xdomeaXmlValues); - doNothing().when(creator).validateZipFileName( - any(), - any(), - any() - ); + doNothing().when(creator).validateZipFileName(any(), any(), any()); + doNothing().when(creator).validatePrimaryDocumentReferences(any(), any()); } @DisplayName("should throw client exception") @@ -165,7 +177,7 @@ class XdomeaXtaMessageCreatorTest { void shouldThrowClientException() { doThrow(technicalException).when(metadataMapper).mapXtaMessageMetadata(xdomeaXmlValues); - assertThatThrownBy(() -> creator.deriveMetaData(xdomeaZipFile)) + assertThatThrownBy(() -> creator.deriveValidMetaData(xdomeaZipFile)) .isInstanceOf(ClientException.class); } @@ -281,4 +293,44 @@ class XdomeaXtaMessageCreatorTest { } + @DisplayName("validate primary document references") + @Nested + class TestValidatePrimaryDocumentReferences { + + private static final List<String> VALID_ZIP_ENTRY_NAMES = List.of("doc.pdf", "doc.xml", "other.doc"); + private static final List<String> INVALID_ZIP_ENTRY_NAMES = List.of("doc.pdf"); + + @Mock + private XtaFile xdomeaZipFile; + + @Mock + private DataHandler contentDataHandler; + + @BeforeEach + @SneakyThrows + void mock() { + when(xdomeaZipFile.content()).thenReturn(contentDataHandler); + + } + + @DisplayName("should not throw exception for valid primary document references") + @Test + @SneakyThrows + void shouldNotThrowExceptionForValidPrimaryDocumentReferences() { + when(zipFileEntryReader.getEntryNames(contentDataHandler)).thenReturn(VALID_ZIP_ENTRY_NAMES); + + creator.validatePrimaryDocumentReferences(xdomeaZipFile, PRIMARY_DOCUMENT_NAMES); + } + + @DisplayName("should throw client exception for missing primary document references") + @Test + @SneakyThrows + void shouldThrowClientExceptionForMissingPrimaryDocumentReferences() { + when(zipFileEntryReader.getEntryNames(contentDataHandler)).thenReturn(INVALID_ZIP_ENTRY_NAMES); + + assertThatThrownBy(() -> creator.validatePrimaryDocumentReferences(xdomeaZipFile, PRIMARY_DOCUMENT_NAMES)) + .isInstanceOf(ClientException.class); + } + } + } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java index 630e4bc0d8cdcfd3aaae7bf7060b6d018339d861..e2fd3afd7e8daf8e5c006b135741a9f77515b190 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java @@ -44,6 +44,9 @@ class XdomeaValueReaderFactoryTest { @Mock XmlValueReader readerIdReader; + @Mock + XmlValueReader primaryDocumentNameReader; + @DisplayName("should return") @Test @SneakyThrows @@ -52,6 +55,7 @@ class XdomeaValueReaderFactoryTest { doReturn(messageTypeReader).when(factory).createXmlValueReader(MESSAGE_TYPE_ID_SUFFIX_XPATH); doReturn(authorIdReader).when(factory).createXmlValueReader(AUTHOR_ID_SUFFIX_XPATH); doReturn(readerIdReader).when(factory).createXmlValueReader(READER_ID_SUFFIX_XPATH); + doReturn(primaryDocumentNameReader).when(factory).createXmlValueReader(PRIMARY_DOCUMENT_NAME_XPATH); var reader = factory.create(); @@ -60,7 +64,8 @@ class XdomeaValueReaderFactoryTest { PROCESS_ID_XPATH, procesIdReader, MESSAGE_TYPE_ID_SUFFIX_XPATH, messageTypeReader, AUTHOR_ID_SUFFIX_XPATH, authorIdReader, - READER_ID_SUFFIX_XPATH, readerIdReader + READER_ID_SUFFIX_XPATH, readerIdReader, + PRIMARY_DOCUMENT_NAME_XPATH, primaryDocumentNameReader )).build()); } } diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java index 99abcbe5940c5fa75aa9ad77f96d37b4632453e2..5b47cc40f94490514007355bef9e10c618a38840 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java @@ -3,8 +3,9 @@ package de.ozgcloud.xta.client.xdomea.reader; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -37,6 +38,7 @@ class XdomeaValueReaderTest { private static final String MESSAGE_TYPE_CODE = "message type code"; private static final String AUTHOR_ID_SUFFIX = "author id suffix"; private static final String READER_ID_SUFFIX = "reader id suffix"; + private static final List<String> PRIMARY_DOCUMENT_NAMES = List.of("primary document name"); @Mock Document xdomeaXmlDocument; @@ -48,6 +50,7 @@ class XdomeaValueReaderTest { doReturn(MESSAGE_TYPE_CODE).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.MESSAGE_TYPE_ID_SUFFIX_XPATH); doReturn(AUTHOR_ID_SUFFIX).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.AUTHOR_ID_SUFFIX_XPATH); doReturn(READER_ID_SUFFIX).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.READER_ID_SUFFIX_XPATH); + doReturn(PRIMARY_DOCUMENT_NAMES).when(xdomeaValueReader).readPrimaryDocumentNames(xdomeaXmlDocument); } @DisplayName("should return process id") @@ -82,12 +85,50 @@ class XdomeaValueReaderTest { assertThat(result.readerIdSuffix()).isEqualTo(READER_ID_SUFFIX); } + @DisplayName("should return primary document names") + @Test + void shouldReturnPrimaryDocumentNames() { + var result = readValues(); + + assertThat(result.primaryDocumentNames()).isEqualTo(PRIMARY_DOCUMENT_NAMES); + } + @SneakyThrows private XdomeaXmlValues readValues() { return xdomeaValueReader.readValues(xdomeaXmlDocument); } } + @DisplayName("read primary document names") + @Nested + class TestReadPrimaryDocumentNames { + + @Mock + XmlValueReader xmlValueReader; + + @Mock + Document xdomeaXmlDocument; + + final String documentName1 = "dou.pdf"; + final String documentName2 = "doc.png"; + + @BeforeEach + void mock() { + doReturn(xmlValueReader).when(xdomeaValueReader).getXmlValueReader(XdomeaValueReader.PRIMARY_DOCUMENT_NAME_XPATH); + } + + @DisplayName("should return") + @Test + @SneakyThrows + void shouldReturn() { + when(xmlValueReader.readNonEmptyTexts(xdomeaXmlDocument)).thenReturn(Stream.of(documentName1, documentName2)); + + var result = xdomeaValueReader.readPrimaryDocumentNames(xdomeaXmlDocument); + + assertThat(result).containsExactly(documentName1, documentName2); + } + } + @DisplayName("read required value") @Nested class TestReadRequiredValue { @@ -109,7 +150,7 @@ class XdomeaValueReaderTest { @Test @SneakyThrows void shouldReturn() { - when(xmlValueReader.readString(xdomeaXmlDocument)).thenReturn(Optional.of(foundValue)); + when(xmlValueReader.readNonEmptyTexts(xdomeaXmlDocument)).thenReturn(Stream.of(foundValue)); var result = xdomeaValueReader.readRequiredValue(xdomeaXmlDocument, XPATH_STRING); @@ -119,7 +160,7 @@ class XdomeaValueReaderTest { @DisplayName("should throw client exception if missing") @Test void shouldThrowClientExceptionIfMissing() { - when(xmlValueReader.readString(xdomeaXmlDocument)).thenReturn(Optional.empty()); + when(xmlValueReader.readNonEmptyTexts(xdomeaXmlDocument)).thenReturn(Stream.empty()); assertThatThrownBy(() -> xdomeaValueReader.readRequiredValue(xdomeaXmlDocument, XPATH_STRING)) .isInstanceOf(ClientException.class); diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactoryTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactoryTest.java index 345df89592accc360d48b4696e376d4ff7ce9f3c..b848a3aea0f792d85c9676b501b53c6b7037eae9 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactoryTest.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderFactoryTest.java @@ -62,7 +62,7 @@ class XmlValueReaderFactoryTest { var result = factory.create(); assertThat(result).usingRecursiveComparison().isEqualTo(XmlValueReader.builder() - .textXpath(expression) + .xPathExpression(expression) .build()); } diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderTest.java index ec8631562e1ff698e96313ff0970efb0c5a8448b..aa059508e802f341efb712d056c235a14d33eb9b 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderTest.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XmlValueReaderTest.java @@ -10,46 +10,46 @@ import org.w3c.dom.Document; public class XmlValueReaderTest { - @DisplayName("read string") + @DisplayName("read non empty texts") @Nested - class TestReadString { + class TestReadNonEmptyTexts { + private static final Document XML_DOCUMENT = createXMLDocument("<root><value attr=\"val\">test</value><value>test2</value></root>"); - private static final Document XML_DOCUMENT = createXMLDocument("<root><value>test</value></root>"); + @DisplayName("should return with two matches") + @Test + void shouldReturnWithTwoMatches() { + var xmlValueReader = createXmlValueReaderWithXPath("/root/value/text()"); - @DisplayName("when xml contains value") - @Nested - class TestWhenXmlContainsValue { + var result = xmlValueReader.readNonEmptyTexts(XML_DOCUMENT); - @DisplayName("should return value") - @Test - void testShouldReturnValue() { - var xmlValueReader = createXmlValueReaderWithXPath("/root/value/text()"); + assertThat(result).containsExactly("test", "test2"); + } - var result = xmlValueReader.readString(XML_DOCUMENT); + @DisplayName("should return with one match") + @Test + void shouldReturnWithOneMatch() { + var xmlValueReader = createXmlValueReaderWithXPath("/root/value[@attr]/text()"); - assertThat(result).contains("test"); - } - } + var result = xmlValueReader.readNonEmptyTexts(XML_DOCUMENT); - @DisplayName("when xml does not contain value") - @Nested - class TestWhenXmlDoesNotContainValue { + assertThat(result).containsExactly("test"); + } - @DisplayName("should return empty") - @Test - void testShouldReturnEmpty() { - var xmlValueReader = createXmlValueReaderWithXPath("/root/missing/text()"); + @DisplayName("should return with no match") + @Test + void shouldReturnWithNoMatch() { + var xmlValueReader = createXmlValueReaderWithXPath("/root/missing/text()"); - var result = xmlValueReader.readString(XML_DOCUMENT); + var result = xmlValueReader.readNonEmptyTexts(XML_DOCUMENT); - assertThat(result).isEmpty(); - } + assertThat(result).isEmpty(); } + } private XmlValueReader createXmlValueReaderWithXPath(String xPathString) { return XmlValueReader.builder() - .textXpath(createXPathExpression(xPathString)) + .xPathExpression(createXPathExpression(xPathString)) .build(); } diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReaderTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReaderTest.java index 31a55f0346f0d6a8fbbd843be14cc4c06843d820..37d1a0346e915cdb7f7ac542cafcbf1c74029470 100644 --- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReaderTest.java +++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/ZipFileEntryReaderTest.java @@ -3,11 +3,13 @@ package de.ozgcloud.xta.client.xdomea.reader; import static de.ozgcloud.xta.client.factory.XtaMessageTestFactory.*; import static org.assertj.core.api.Assertions.*; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.function.Function; import jakarta.activation.DataHandler; +import jakarta.activation.FileDataSource; import jakarta.mail.util.ByteArrayDataSource; import org.junit.jupiter.api.DisplayName; @@ -24,14 +26,13 @@ class ZipFileEntryReaderTest { private final ZipFileEntryReader reader = ZipFileEntryReaderFactory.builder().build().create(); - @DisplayName("map entry data") @Nested class TestMapEntryData { private final Function<InputStream, String> inputStreamConsumer = inputStream -> { try { - var data= inputStream.readAllBytes(); + var data = inputStream.readAllBytes(); return new String(data); } catch (IOException e) { throw new RuntimeException(e); @@ -61,6 +62,35 @@ class ZipFileEntryReaderTest { } } + @DisplayName("get entry names") + @Nested + class TestGetEntryNames { + + @DisplayName("should return entry names") + @Test + void shouldReturnEntryNames() { + var entryNames = reader.getEntryNames(ZIP_FILE); + + assertThat(entryNames).containsExactlyInAnyOrder( + "66a7635a-3872-3519-5ad8-00000000e7db_small_png.png", + "66a76331-3872-3519-5ad8-00000000e7d8_XML-Daten.xml", + "66a76372-3872-3519-5ad8-00000000e7df_Tempo.pdf", + "84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.xml" + ); + } + + @DisplayName("should throw exception on bad zip file") + @Test + void shouldThrowExceptionOnBadZipFile() { + assertThatThrownBy(() -> reader.getEntryNames(createMissingFileDataHandler())) + .isInstanceOf(TechnicalException.class); + } + + private static DataHandler createMissingFileDataHandler() { + return new DataHandler(new FileDataSource(new File("missing-file"))); + } + } + private static DataHandler createContentDataHandler(byte[] data) { return new DataHandler(new ByteArrayDataSource(data, "application/octet-stream")); } diff --git a/src/test/resources/messages/abgabe0401-kleiner-waffenschein/invalid-reference-to-primary-document.patch b/src/test/resources/messages/abgabe0401-kleiner-waffenschein/invalid-reference-to-primary-document.patch new file mode 100644 index 0000000000000000000000000000000000000000..6df712f6ee1e31b30c12873dcef1ffe33e495d91 --- /dev/null +++ b/src/test/resources/messages/abgabe0401-kleiner-waffenschein/invalid-reference-to-primary-document.patch @@ -0,0 +1,13 @@ +diff --git a/src/test/resources/messages/abgabe0401-kleiner-waffenschein/message/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.zip/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.xml b/src/test/resources/messages/abgabe0401-kleiner-waffenschein/message/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.zip/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.xml +index cac00bf..9103baa 100644 +--- a/src/test/resources/messages/abgabe0401-kleiner-waffenschein/message/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.zip/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.xml ++++ b/src/test/resources/messages/abgabe0401-kleiner-waffenschein/message/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.zip/84be3140-e069-4d4a-80c7-889b5eec539e_Abgabe.Abgabe.0401.xml +@@ -158,7 +158,7 @@ + </xdomea:Name> + <xdomea:Version></xdomea:Version> + <xdomea:Primaerdokument> +- <xdomea:Dateiname>66a7635a-3872-3519-5ad8-00000000e7db_small_png.png</xdomea:Dateiname> ++ <xdomea:Dateiname>66a7635a-3872-3519-5ad8-00000000e7db_unkonwn_png.png</xdomea:Dateiname> + <xdomea:DateinameOriginal>small_png.png</xdomea:DateinameOriginal> + </xdomea:Primaerdokument> + </xdomea:Format>