From a287cd45068e4423cea1c11de8c991a6f4e1f7b6 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Thu, 7 Dec 2023 10:16:38 +0100 Subject: [PATCH 1/8] Show log output in tests and add getErrorMessages --- .../interlis/testbed/runner/RunnerTest.java | 14 ++++---------- .../interlis/testbed/runner/TestLogAppender.java | 16 +++++++++++----- src/test/resources/log4j2-test.xml | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 src/test/resources/log4j2-test.xml diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/RunnerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/RunnerTest.java index 579cca3..8fae6dc 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/RunnerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/RunnerTest.java @@ -1,6 +1,5 @@ package ch.geowerkstatt.interlis.testbed.runner; -import org.apache.logging.log4j.Level; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,10 +53,8 @@ public void runValidatesBaseData() throws IOException { var expectedFiles = List.of(expectedBaseDataFile); assertIterableEquals(expectedFiles, validatedFiles); - var errors = appender.getMessages() - .stream() - .filter(e -> e.level().equals(Level.ERROR)); - assertEquals(0, errors.count(), "No errors should have been logged."); + var errors = appender.getErrorMessages(); + assertEquals(0, errors.size(), "No errors should have been logged."); } @Test @@ -68,11 +65,8 @@ public void runLogsValidationError() { assertFalse(runResult, "Testbed run should have failed."); - var errors = appender.getMessages() - .stream() - .filter(e -> e.level().equals(Level.ERROR)) - .toList(); + var errors = appender.getErrorMessages(); assertEquals(1, errors.size(), "One error should have been logged."); - assertEquals("Validation of base data failed.", errors.get(0).message()); + assertEquals("Validation of base data failed.", errors.getFirst()); } } diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/TestLogAppender.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/TestLogAppender.java index 8e0e0bd..f69bc9c 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/TestLogAppender.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/TestLogAppender.java @@ -26,14 +26,13 @@ private TestLogAppender(Class loggerClass) { } public static TestLogAppender registerAppender(Class loggerClass) { - var mockedAppender = new TestLogAppender(loggerClass); + var testLogAppender = new TestLogAppender(loggerClass); + testLogAppender.start(); var logger = (Logger) LogManager.getLogger(loggerClass); - logger.addAppender(mockedAppender); - logger.setLevel(Level.ALL); + logger.get().addAppender(testLogAppender, Level.ALL, null); - mockedAppender.start(); - return mockedAppender; + return testLogAppender; } public void unregister() { @@ -45,6 +44,13 @@ public List getMessages() { return messages; } + public List getErrorMessages() { + return messages.stream() + .filter(e -> e.level().equals(Level.ERROR)) + .map(LogEntry::message) + .toList(); + } + @Override public void append(LogEvent event) { messages.add(new LogEntry(event.getLevel(), event.getMessage().getFormattedMessage())); diff --git a/src/test/resources/log4j2-test.xml b/src/test/resources/log4j2-test.xml new file mode 100644 index 0000000..eb9b6c4 --- /dev/null +++ b/src/test/resources/log4j2-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From a9544f6a9881e7d432ba3ac56d7fc78422f14cb5 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Thu, 7 Dec 2023 15:00:08 +0100 Subject: [PATCH 2/8] Add XtfFileMerger to combine base data and patches --- .gitignore | 3 + .../interlis/testbed/runner/xtf/Basket.java | 23 +++ .../testbed/runner/xtf/XtfFileMerger.java | 157 ++++++++++++++++++ .../testbed/runner/xtf/XtfMerger.java | 15 ++ src/test/data/xtf-merger/data.xtf | 27 +++ src/test/data/xtf-merger/patch.xtf | 15 ++ .../testbed/runner/xtf/XtfFileMergerTest.java | 61 +++++++ 7 files changed, 301 insertions(+) create mode 100644 src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java create mode 100644 src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java create mode 100644 src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfMerger.java create mode 100644 src/test/data/xtf-merger/data.xtf create mode 100644 src/test/data/xtf-merger/patch.xtf create mode 100644 src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java diff --git a/.gitignore b/.gitignore index 3348a20..7ba7fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ build/ !**/src/main/**/build/ !**/src/test/**/build/ +# Files generated by interlis-testbed-runner +output/ + ### IntelliJ IDEA ### .idea/modules.xml .idea/jarRepositories.xml diff --git a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java new file mode 100644 index 0000000..2aa4f08 --- /dev/null +++ b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java @@ -0,0 +1,23 @@ +package ch.geowerkstatt.interlis.testbed.runner.xtf; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import java.util.Map; + +public record Basket(Element element, Map objects) { + /** + * Adds or replaces the child node with the given entry ID. + * + * @param entryId the entry ID + * @param node the node to add or replace + */ + public void addOrReplaceChild(String entryId, Node node) { + var originalEntry = objects().get(entryId); + if (originalEntry == null) { + element().appendChild(node); + } else { + element().replaceChild(node, originalEntry); + } + } +} diff --git a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java new file mode 100644 index 0000000..a63d441 --- /dev/null +++ b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java @@ -0,0 +1,157 @@ +package ch.geowerkstatt.interlis.testbed.runner.xtf; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public final class XtfFileMerger implements XtfMerger { + private static final Logger LOGGER = LogManager.getLogger(); + private static final String BASKET_ID = "BID"; + private static final String OBJECT_ID = "TID"; + + private final DocumentBuilderFactory factory; + + /** + * Creates a new instance of the XtfFileMerger class. + */ + public XtfFileMerger() { + factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + } + + @Override + public boolean merge(Path baseFile, Path patchFile, Path outputFile) { + try { + LOGGER.info("Merging " + baseFile + " with " + patchFile + " into " + outputFile); + var documentBuilder = createDocumentBuilder(); + + var baseDocument = documentBuilder.parse(baseFile.toFile()); + var patchDocument = documentBuilder.parse(patchFile.toFile()); + + var baseBaskets = findBaskets(baseDocument); + if (baseBaskets.isEmpty()) { + LOGGER.error("No baskets found in base file " + baseFile + "."); + return false; + } + + var patchBaskets = findBaskets(patchDocument); + if (patchBaskets.isEmpty()) { + LOGGER.error("No baskets found in patch file " + patchFile + "."); + return false; + } + + if (!mergeBaskets(baseDocument, baseBaskets.get(), patchBaskets.get())) { + return false; + } + + writeMergedFile(baseDocument, outputFile); + LOGGER.info("Successfully merged files into " + outputFile); + return true; + } catch (Exception e) { + LOGGER.error("Failed to merge files.", e); + return false; + } + } + + DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { + return factory.newDocumentBuilder(); + } + + private static boolean mergeBaskets(Document document, Map baseBaskets, Map patchBaskets) { + var isValid = true; + + for (var patchBasket : patchBaskets.entrySet()) { + var basketId = patchBasket.getKey(); + + var originalBasket = baseBaskets.get(basketId); + if (originalBasket == null) { + LOGGER.error("Basket " + basketId + " not found in base file."); + isValid = false; + continue; + } + + for (var patchEntry : patchBasket.getValue().objects().entrySet()) { + var entryId = patchEntry.getKey(); + + var importedNode = document.importNode(patchEntry.getValue(), true); + originalBasket.addOrReplaceChild(entryId, importedNode); + } + } + + return isValid; + } + + private static void writeMergedFile(Document document, Path outputFile) throws IOException, TransformerException { + Files.createDirectories(outputFile.getParent()); + + var transformerFactory = TransformerFactory.newInstance(); + var transformer = transformerFactory.newTransformer(); + var source = new DOMSource(document); + var result = new StreamResult(outputFile.toFile()); + transformer.transform(source, result); + } + + static Optional> findBaskets(Document document) { + var dataSection = findDataSection(document); + if (dataSection.isEmpty()) { + return Optional.empty(); + } + + var baskets = streamChildElementNodes(dataSection.get()) + .filter(e -> { + var hasId = e.hasAttribute(BASKET_ID); + if (!hasId) { + LOGGER.warn("Basket without " + BASKET_ID + " found."); + } + return hasId; + }) + .collect(Collectors.toMap(e -> e.getAttribute(BASKET_ID), XtfFileMerger::collectBasket)); + return Optional.of(baskets); + } + + private static Basket collectBasket(Element basket) { + var objects = streamChildElementNodes(basket) + .filter(e -> { + var hasId = e.hasAttribute(OBJECT_ID); + if (!hasId) { + LOGGER.warn("Entry without " + OBJECT_ID + " found in basket " + basket.getAttribute(BASKET_ID) + "."); + } + return hasId; + }) + .collect(Collectors.toMap(e -> e.getAttribute(OBJECT_ID), e -> e)); + return new Basket(basket, objects); + } + + private static Optional findDataSection(Document document) { + var transfer = document.getFirstChild(); + return streamChildElementNodes(transfer) + .filter(n -> n.getLocalName().equalsIgnoreCase("datasection")) + .findFirst(); + } + + private static Stream streamChildElementNodes(Node node) { + var childNodes = node.getChildNodes(); + return IntStream.range(0, childNodes.getLength()) + .mapToObj(childNodes::item) + .filter(n -> n instanceof Element) + .map(n -> (Element) n); + } +} diff --git a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfMerger.java b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfMerger.java new file mode 100644 index 0000000..189252b --- /dev/null +++ b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfMerger.java @@ -0,0 +1,15 @@ +package ch.geowerkstatt.interlis.testbed.runner.xtf; + +import java.nio.file.Path; + +public interface XtfMerger { + /** + * Merges the patch file into the base file and writes the result to the output file. + * + * @param baseFile the base file + * @param patchFile the patch file + * @param outputFile the output file + * @return {@code true} if the merge was successful, {@code false} otherwise. + */ + boolean merge(Path baseFile, Path patchFile, Path outputFile); +} diff --git a/src/test/data/xtf-merger/data.xtf b/src/test/data/xtf-merger/data.xtf new file mode 100644 index 0000000..365a10b --- /dev/null +++ b/src/test/data/xtf-merger/data.xtf @@ -0,0 +1,27 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + Some text + Some more text + + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/patch.xtf b/src/test/data/xtf-merger/patch.xtf new file mode 100644 index 0000000..96b98d6 --- /dev/null +++ b/src/test/data/xtf-merger/patch.xtf @@ -0,0 +1,15 @@ + + + + + + New value for attr1 + + + + New entry + Attr2 + + + + diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java new file mode 100644 index 0000000..ff93861 --- /dev/null +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -0,0 +1,61 @@ +package ch.geowerkstatt.interlis.testbed.runner.xtf; + +import ch.geowerkstatt.interlis.testbed.runner.TestLogAppender; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public final class XtfFileMergerTest { + private static final String BASE_PATH = "src/test/data/xtf-merger"; + + private TestLogAppender appender; + + @BeforeEach + public void setup() { + appender = TestLogAppender.registerAppender(XtfFileMerger.class); + } + + @AfterEach + public void teardown() { + appender.stop(); + appender.unregister(); + } + + @Test + public void validateMergedXtf() throws Exception { + var baseFile = Path.of(BASE_PATH, "data.xtf"); + var patchFile = Path.of(BASE_PATH, "patch.xtf"); + var outputFile = Path.of(BASE_PATH, "output", "merged.xtf"); + + var merger = new XtfFileMerger(); + + var mergeResult = merger.merge(baseFile, patchFile, outputFile); + + assertTrue(mergeResult, "Merging should have been successful."); + assertTrue(Files.exists(outputFile), "Output file should have been created."); + + assertEquals(0, appender.getErrorMessages().size(), "No errors should have been logged."); + + var documentBuilder = merger.createDocumentBuilder(); + var mergedDocument = documentBuilder.parse(outputFile.toFile()); + var baskets = XtfFileMerger.findBaskets(mergedDocument); + assertTrue(baskets.isPresent(), "Baskets should have been found in merged file."); + + var b1 = baskets.get().get("B1"); + assertNotNull(b1, "Basket B1 should have been found in merged file."); + assertIterableEquals(List.of("A1", "A2", "A3"), b1.objects().keySet()); + + var b2 = baskets.get().get("B2"); + assertNotNull(b2, "Basket B2 should have been found in merged file."); + assertIterableEquals(List.of("A1"), b2.objects().keySet()); + } +} From 0cfaf9a5f5431454f3840cdeec1d8f239c7e7515 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Thu, 7 Dec 2023 16:18:54 +0100 Subject: [PATCH 3/8] Support INTERLIS 2.3 and 2.4 transfer files --- .../testbed/runner/xtf/XtfFileMerger.java | 25 ++++++++++++++--- src/test/data/xtf-merger/{ => ili23}/data.xtf | 17 ++++++------ .../data/xtf-merger/{ => ili23}/patch.xtf | 8 +++--- src/test/data/xtf-merger/ili24/data.xtf | 27 +++++++++++++++++++ src/test/data/xtf-merger/ili24/patch.xtf | 15 +++++++++++ .../testbed/runner/xtf/XtfFileMergerTest.java | 14 +++++----- 6 files changed, 83 insertions(+), 23 deletions(-) rename src/test/data/xtf-merger/{ => ili23}/data.xtf (70%) rename src/test/data/xtf-merger/{ => ili23}/patch.xtf (77%) create mode 100644 src/test/data/xtf-merger/ili24/data.xtf create mode 100644 src/test/data/xtf-merger/ili24/patch.xtf diff --git a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java index a63d441..35f122e 100644 --- a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java +++ b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java @@ -26,6 +26,7 @@ public final class XtfFileMerger implements XtfMerger { private static final Logger LOGGER = LogManager.getLogger(); private static final String BASKET_ID = "BID"; private static final String OBJECT_ID = "TID"; + private static final String INTERLIS24_NAMESPACE = "http://www.interlis.ch/xtf/2.4/INTERLIS"; private final DocumentBuilderFactory factory; @@ -117,29 +118,45 @@ static Optional> findBaskets(Document document) { var baskets = streamChildElementNodes(dataSection.get()) .filter(e -> { - var hasId = e.hasAttribute(BASKET_ID); + var hasId = hasInterlisAttribute(e, BASKET_ID); if (!hasId) { LOGGER.warn("Basket without " + BASKET_ID + " found."); } return hasId; }) - .collect(Collectors.toMap(e -> e.getAttribute(BASKET_ID), XtfFileMerger::collectBasket)); + .collect(Collectors.toMap(e -> getInterlisAttribute(e, BASKET_ID), XtfFileMerger::collectBasket)); return Optional.of(baskets); } private static Basket collectBasket(Element basket) { var objects = streamChildElementNodes(basket) .filter(e -> { - var hasId = e.hasAttribute(OBJECT_ID); + var hasId = hasInterlisAttribute(e, OBJECT_ID); if (!hasId) { LOGGER.warn("Entry without " + OBJECT_ID + " found in basket " + basket.getAttribute(BASKET_ID) + "."); } return hasId; }) - .collect(Collectors.toMap(e -> e.getAttribute(OBJECT_ID), e -> e)); + .collect(Collectors.toMap(e -> getInterlisAttribute(e, OBJECT_ID), e -> e)); return new Basket(basket, objects); } + private static boolean hasInterlisAttribute(Element element, String attributeName) { + return getInterlisAttribute(element, attributeName) != null; + } + + private static String getInterlisAttribute(Element element, String attributeName) { + if (element.hasAttribute(attributeName)) { + return element.getAttribute(attributeName); + } + + var ili24Name = attributeName.toLowerCase(); + if (element.hasAttributeNS(INTERLIS24_NAMESPACE, ili24Name)) { + return element.getAttributeNS(INTERLIS24_NAMESPACE, ili24Name); + } + return null; + } + private static Optional findDataSection(Document document) { var transfer = document.getFirstChild(); return streamChildElementNodes(transfer) diff --git a/src/test/data/xtf-merger/data.xtf b/src/test/data/xtf-merger/ili23/data.xtf similarity index 70% rename from src/test/data/xtf-merger/data.xtf rename to src/test/data/xtf-merger/ili23/data.xtf index 365a10b..e552f67 100644 --- a/src/test/data/xtf-merger/data.xtf +++ b/src/test/data/xtf-merger/ili23/data.xtf @@ -1,11 +1,10 @@ - - - - - interlis-testbed-runner - - + + + + + + Some text @@ -23,5 +22,5 @@ Some more text - - + + diff --git a/src/test/data/xtf-merger/patch.xtf b/src/test/data/xtf-merger/ili23/patch.xtf similarity index 77% rename from src/test/data/xtf-merger/patch.xtf rename to src/test/data/xtf-merger/ili23/patch.xtf index 96b98d6..4380823 100644 --- a/src/test/data/xtf-merger/patch.xtf +++ b/src/test/data/xtf-merger/ili23/patch.xtf @@ -1,6 +1,6 @@ - - + + New value for attr1 @@ -11,5 +11,5 @@ Attr2 - - + + diff --git a/src/test/data/xtf-merger/ili24/data.xtf b/src/test/data/xtf-merger/ili24/data.xtf new file mode 100644 index 0000000..33f2bb1 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/data.xtf @@ -0,0 +1,27 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + Some text + Some more text + + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/ili24/patch.xtf b/src/test/data/xtf-merger/ili24/patch.xtf new file mode 100644 index 0000000..5e3cea8 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/patch.xtf @@ -0,0 +1,15 @@ + + + + + + New value for attr1 + + + + New entry + Attr2 + + + + diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java index ff93861..6bf01ee 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -3,7 +3,8 @@ import ch.geowerkstatt.interlis.testbed.runner.TestLogAppender; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.nio.file.Files; import java.nio.file.Path; @@ -30,11 +31,12 @@ public void teardown() { appender.unregister(); } - @Test - public void validateMergedXtf() throws Exception { - var baseFile = Path.of(BASE_PATH, "data.xtf"); - var patchFile = Path.of(BASE_PATH, "patch.xtf"); - var outputFile = Path.of(BASE_PATH, "output", "merged.xtf"); + @ParameterizedTest + @ValueSource(strings = {"ili23", "ili24"}) + public void validateMergedXtf(String iliVersion) throws Exception { + var baseFile = Path.of(BASE_PATH, iliVersion, "data.xtf"); + var patchFile = Path.of(BASE_PATH, iliVersion, "patch.xtf"); + var outputFile = Path.of(BASE_PATH, iliVersion, "output", "merged.xtf"); var merger = new XtfFileMerger(); From 36121c33e6239fa6a3525f6c7326bb37f4c3f57a Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Mon, 11 Dec 2023 08:43:09 +0100 Subject: [PATCH 4/8] Compare merged xtf files to expectation using xmlunit --- build.gradle | 1 + src/test/data/xtf-merger/ili23/expected.xtf | 30 ++++++++++++++ src/test/data/xtf-merger/ili24/expected.xtf | 31 +++++++++++++++ .../testbed/runner/xtf/XtfFileMergerTest.java | 39 ++++++++++++------- 4 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 src/test/data/xtf-merger/ili23/expected.xtf create mode 100644 src/test/data/xtf-merger/ili24/expected.xtf diff --git a/build.gradle b/build.gradle index 6f4e828..26b6967 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,7 @@ dependencies { testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.xmlunit:xmlunit-core:2.9.1' } application { diff --git a/src/test/data/xtf-merger/ili23/expected.xtf b/src/test/data/xtf-merger/ili23/expected.xtf new file mode 100644 index 0000000..956045d --- /dev/null +++ b/src/test/data/xtf-merger/ili23/expected.xtf @@ -0,0 +1,30 @@ + + + + + + + + + + Some text + Some more text + + + New value for attr1 + + + + New entry + Attr2 + + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/ili24/expected.xtf b/src/test/data/xtf-merger/ili24/expected.xtf new file mode 100644 index 0000000..74d1175 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/expected.xtf @@ -0,0 +1,31 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + New value for attr1 + + + + New entry + Attr2 + + + + + + Some text + Some more text + + + + diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java index 6bf01ee..7063a07 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -5,14 +5,16 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.xmlunit.builder.DiffBuilder; +import org.xmlunit.diff.DefaultNodeMatcher; +import org.xmlunit.diff.ElementSelectors; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public final class XtfFileMergerTest { @@ -36,6 +38,7 @@ public void teardown() { public void validateMergedXtf(String iliVersion) throws Exception { var baseFile = Path.of(BASE_PATH, iliVersion, "data.xtf"); var patchFile = Path.of(BASE_PATH, iliVersion, "patch.xtf"); + var expectedFile = Path.of(BASE_PATH, iliVersion, "expected.xtf"); var outputFile = Path.of(BASE_PATH, iliVersion, "output", "merged.xtf"); var merger = new XtfFileMerger(); @@ -47,17 +50,27 @@ public void validateMergedXtf(String iliVersion) throws Exception { assertEquals(0, appender.getErrorMessages().size(), "No errors should have been logged."); - var documentBuilder = merger.createDocumentBuilder(); - var mergedDocument = documentBuilder.parse(outputFile.toFile()); - var baskets = XtfFileMerger.findBaskets(mergedDocument); - assertTrue(baskets.isPresent(), "Baskets should have been found in merged file."); + assertEqualXtfFiles(expectedFile, outputFile); + } + + private void assertEqualXtfFiles(Path expectedFile, Path actualFile) throws IOException { + var expectedXml = Files.readString(expectedFile); + var actualXml = Files.readString(actualFile); + + var nodeMatcher = new DefaultNodeMatcher(ElementSelectors.byNameAndText); + var diff = DiffBuilder + .compare(expectedXml) + .withTest(actualXml) + .checkForSimilar() + .withNodeMatcher(nodeMatcher) + .ignoreWhitespace() + .ignoreComments() + .build(); - var b1 = baskets.get().get("B1"); - assertNotNull(b1, "Basket B1 should have been found in merged file."); - assertIterableEquals(List.of("A1", "A2", "A3"), b1.objects().keySet()); + for (var difference : diff.getDifferences()) { + System.out.println(difference); + } - var b2 = baskets.get().get("B2"); - assertNotNull(b2, "Basket B2 should have been found in merged file."); - assertIterableEquals(List.of("A1"), b2.objects().keySet()); + assertFalse(diff.hasDifferences(), "Expected and actual XTF files should be equal."); } } From 692e6ea23d16c7ea1d25fc6b994557756dcadb90 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Mon, 11 Dec 2023 09:12:08 +0100 Subject: [PATCH 5/8] Move XtfMerger test files into subfolder and add line attribute --- .../xtf-merger/ili23/{ => combined}/data.xtf | 18 +++++- .../xtf-merger/ili23/combined/expected.xtf | 54 ++++++++++++++++++ .../data/xtf-merger/ili23/combined/patch.xtf | 27 +++++++++ src/test/data/xtf-merger/ili23/expected.xtf | 30 ---------- src/test/data/xtf-merger/ili23/patch.xtf | 15 ----- .../xtf-merger/ili24/{ => combined}/data.xtf | 20 +++++-- .../xtf-merger/ili24/combined/expected.xtf | 55 +++++++++++++++++++ .../data/xtf-merger/ili24/combined/patch.xtf | 27 +++++++++ src/test/data/xtf-merger/ili24/expected.xtf | 31 ----------- src/test/data/xtf-merger/ili24/patch.xtf | 15 ----- .../testbed/runner/xtf/XtfFileMergerTest.java | 16 ++++-- 11 files changed, 204 insertions(+), 104 deletions(-) rename src/test/data/xtf-merger/ili23/{ => combined}/data.xtf (58%) create mode 100644 src/test/data/xtf-merger/ili23/combined/expected.xtf create mode 100644 src/test/data/xtf-merger/ili23/combined/patch.xtf delete mode 100644 src/test/data/xtf-merger/ili23/expected.xtf delete mode 100644 src/test/data/xtf-merger/ili23/patch.xtf rename src/test/data/xtf-merger/ili24/{ => combined}/data.xtf (52%) create mode 100644 src/test/data/xtf-merger/ili24/combined/expected.xtf create mode 100644 src/test/data/xtf-merger/ili24/combined/patch.xtf delete mode 100644 src/test/data/xtf-merger/ili24/expected.xtf delete mode 100644 src/test/data/xtf-merger/ili24/patch.xtf diff --git a/src/test/data/xtf-merger/ili23/data.xtf b/src/test/data/xtf-merger/ili23/combined/data.xtf similarity index 58% rename from src/test/data/xtf-merger/ili23/data.xtf rename to src/test/data/xtf-merger/ili23/combined/data.xtf index e552f67..de9d3af 100644 --- a/src/test/data/xtf-merger/ili23/data.xtf +++ b/src/test/data/xtf-merger/ili23/combined/data.xtf @@ -6,18 +6,30 @@ - + Some text Some more text + + + + 1.0 + 2.0 + + + 1.5 + 2.5 + + + - + Some text Some more text - + Some text Some more text diff --git a/src/test/data/xtf-merger/ili23/combined/expected.xtf b/src/test/data/xtf-merger/ili23/combined/expected.xtf new file mode 100644 index 0000000..0ab6b78 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/combined/expected.xtf @@ -0,0 +1,54 @@ + + + + + + + + + + Some text + Some more text + + + + 1.0 + 2.0 + + + 1.5 + 2.5 + + + + + + New value for attr1 + + + + + 10.0 + 20.0 + + + 100.0 + 20.0 + + + + + + New entry + Attr2 + + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/ili23/combined/patch.xtf b/src/test/data/xtf-merger/ili23/combined/patch.xtf new file mode 100644 index 0000000..c88cd9f --- /dev/null +++ b/src/test/data/xtf-merger/ili23/combined/patch.xtf @@ -0,0 +1,27 @@ + + + + + + New value for attr1 + + + + + 10.0 + 20.0 + + + 100.0 + 20.0 + + + + + + New entry + Attr2 + + + + diff --git a/src/test/data/xtf-merger/ili23/expected.xtf b/src/test/data/xtf-merger/ili23/expected.xtf deleted file mode 100644 index 956045d..0000000 --- a/src/test/data/xtf-merger/ili23/expected.xtf +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - Some text - Some more text - - - New value for attr1 - - - - New entry - Attr2 - - - - - - Some text - Some more text - - - - diff --git a/src/test/data/xtf-merger/ili23/patch.xtf b/src/test/data/xtf-merger/ili23/patch.xtf deleted file mode 100644 index 4380823..0000000 --- a/src/test/data/xtf-merger/ili23/patch.xtf +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - New value for attr1 - - - - New entry - Attr2 - - - - diff --git a/src/test/data/xtf-merger/ili24/data.xtf b/src/test/data/xtf-merger/ili24/combined/data.xtf similarity index 52% rename from src/test/data/xtf-merger/ili24/data.xtf rename to src/test/data/xtf-merger/ili24/combined/data.xtf index 33f2bb1..91cd39b 100644 --- a/src/test/data/xtf-merger/ili24/data.xtf +++ b/src/test/data/xtf-merger/ili24/combined/data.xtf @@ -1,5 +1,5 @@ - + @@ -7,18 +7,30 @@ - + Some text Some more text + + + + 1.0 + 2.0 + + + 1.5 + 2.5 + + + - + Some text Some more text - + Some text Some more text diff --git a/src/test/data/xtf-merger/ili24/combined/expected.xtf b/src/test/data/xtf-merger/ili24/combined/expected.xtf new file mode 100644 index 0000000..9510658 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/combined/expected.xtf @@ -0,0 +1,55 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + + 1.0 + 2.0 + + + 1.5 + 2.5 + + + + + + New value for attr1 + + + + + 10.0 + 20.0 + + + 100.0 + 20.0 + + + + + + New entry + Attr2 + + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/ili24/combined/patch.xtf b/src/test/data/xtf-merger/ili24/combined/patch.xtf new file mode 100644 index 0000000..6648570 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/combined/patch.xtf @@ -0,0 +1,27 @@ + + + + + + New value for attr1 + + + + + 10.0 + 20.0 + + + 100.0 + 20.0 + + + + + + New entry + Attr2 + + + + diff --git a/src/test/data/xtf-merger/ili24/expected.xtf b/src/test/data/xtf-merger/ili24/expected.xtf deleted file mode 100644 index 74d1175..0000000 --- a/src/test/data/xtf-merger/ili24/expected.xtf +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - interlis-testbed-runner - - - - - Some text - Some more text - - - New value for attr1 - - - - New entry - Attr2 - - - - - - Some text - Some more text - - - - diff --git a/src/test/data/xtf-merger/ili24/patch.xtf b/src/test/data/xtf-merger/ili24/patch.xtf deleted file mode 100644 index 5e3cea8..0000000 --- a/src/test/data/xtf-merger/ili24/patch.xtf +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - New value for attr1 - - - - New entry - Attr2 - - - - diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java index 7063a07..d4ea499 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public final class XtfFileMergerTest { - private static final String BASE_PATH = "src/test/data/xtf-merger"; + private static final String DATA_BASE_PATH = "src/test/data/xtf-merger"; private TestLogAppender appender; @@ -35,11 +35,15 @@ public void teardown() { @ParameterizedTest @ValueSource(strings = {"ili23", "ili24"}) - public void validateMergedXtf(String iliVersion) throws Exception { - var baseFile = Path.of(BASE_PATH, iliVersion, "data.xtf"); - var patchFile = Path.of(BASE_PATH, iliVersion, "patch.xtf"); - var expectedFile = Path.of(BASE_PATH, iliVersion, "expected.xtf"); - var outputFile = Path.of(BASE_PATH, iliVersion, "output", "merged.xtf"); + public void combinedOperations(String iliVersion) throws IOException { + mergeAndValidateXtf(Path.of(DATA_BASE_PATH, iliVersion, "combined")); + } + + private void mergeAndValidateXtf(Path basePath) throws IOException { + var baseFile = basePath.resolve("data.xtf"); + var patchFile = basePath.resolve("patch.xtf"); + var expectedFile = basePath.resolve("expected.xtf"); + var outputFile = basePath.resolve("output").resolve("merged.xtf"); var merger = new XtfFileMerger(); From a02d65a6b2358d2bab6872f2e05785a6055799af Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Mon, 11 Dec 2023 09:13:51 +0100 Subject: [PATCH 6/8] Add XtfMerger tests to add new elements --- src/test/data/xtf-merger/ili23/add/data.xtf | 25 ++++++++++++++ .../data/xtf-merger/ili23/add/expected.xtf | 33 ++++++++++++++++++ src/test/data/xtf-merger/ili23/add/patch.xtf | 18 ++++++++++ src/test/data/xtf-merger/ili24/add/data.xtf | 26 ++++++++++++++ .../data/xtf-merger/ili24/add/expected.xtf | 34 +++++++++++++++++++ src/test/data/xtf-merger/ili24/add/patch.xtf | 18 ++++++++++ .../testbed/runner/xtf/XtfFileMergerTest.java | 6 ++++ 7 files changed, 160 insertions(+) create mode 100644 src/test/data/xtf-merger/ili23/add/data.xtf create mode 100644 src/test/data/xtf-merger/ili23/add/expected.xtf create mode 100644 src/test/data/xtf-merger/ili23/add/patch.xtf create mode 100644 src/test/data/xtf-merger/ili24/add/data.xtf create mode 100644 src/test/data/xtf-merger/ili24/add/expected.xtf create mode 100644 src/test/data/xtf-merger/ili24/add/patch.xtf diff --git a/src/test/data/xtf-merger/ili23/add/data.xtf b/src/test/data/xtf-merger/ili23/add/data.xtf new file mode 100644 index 0000000..a36bbe4 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/add/data.xtf @@ -0,0 +1,25 @@ + + + + + + + + + + Some text + Some more text + + + + + + Some text + Some more text + + + + + + + diff --git a/src/test/data/xtf-merger/ili23/add/expected.xtf b/src/test/data/xtf-merger/ili23/add/expected.xtf new file mode 100644 index 0000000..1639735 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/add/expected.xtf @@ -0,0 +1,33 @@ + + + + + + + + + + Some text + Some more text + + + New entry + Attr2 + + + + + + Some text + Some more text + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/data/xtf-merger/ili23/add/patch.xtf b/src/test/data/xtf-merger/ili23/add/patch.xtf new file mode 100644 index 0000000..7449ab4 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/add/patch.xtf @@ -0,0 +1,18 @@ + + + + + + New entry + Attr2 + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/data/xtf-merger/ili24/add/data.xtf b/src/test/data/xtf-merger/ili24/add/data.xtf new file mode 100644 index 0000000..b7000de --- /dev/null +++ b/src/test/data/xtf-merger/ili24/add/data.xtf @@ -0,0 +1,26 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + + + + Some text + Some more text + + + + + + + diff --git a/src/test/data/xtf-merger/ili24/add/expected.xtf b/src/test/data/xtf-merger/ili24/add/expected.xtf new file mode 100644 index 0000000..69717a1 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/add/expected.xtf @@ -0,0 +1,34 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + New entry + Attr2 + + + + + + Some text + Some more text + + + + + + Attribute 1 + Attribute 2 + + + + \ No newline at end of file diff --git a/src/test/data/xtf-merger/ili24/add/patch.xtf b/src/test/data/xtf-merger/ili24/add/patch.xtf new file mode 100644 index 0000000..c3f38af --- /dev/null +++ b/src/test/data/xtf-merger/ili24/add/patch.xtf @@ -0,0 +1,18 @@ + + + + + + New entry + Attr2 + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java index d4ea499..6fce7dd 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -33,6 +33,12 @@ public void teardown() { appender.unregister(); } + @ParameterizedTest + @ValueSource(strings = {"ili23", "ili24"}) + public void addElements(String iliVersion) throws IOException { + mergeAndValidateXtf(Path.of(DATA_BASE_PATH, iliVersion, "add")); + } + @ParameterizedTest @ValueSource(strings = {"ili23", "ili24"}) public void combinedOperations(String iliVersion) throws IOException { From 65aa6ecb62b5a03467669225d932b87520f15699 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Mon, 11 Dec 2023 10:08:57 +0100 Subject: [PATCH 7/8] Add XtfMerger tests to replace elements --- .../data/xtf-merger/ili23/replace/data.xtf | 22 +++++++++++++++++ .../xtf-merger/ili23/replace/expected.xtf | 23 ++++++++++++++++++ .../data/xtf-merger/ili23/replace/patch.xtf | 12 ++++++++++ .../data/xtf-merger/ili24/replace/data.xtf | 23 ++++++++++++++++++ .../xtf-merger/ili24/replace/expected.xtf | 24 +++++++++++++++++++ .../data/xtf-merger/ili24/replace/patch.xtf | 12 ++++++++++ .../testbed/runner/xtf/XtfFileMergerTest.java | 6 +++++ 7 files changed, 122 insertions(+) create mode 100644 src/test/data/xtf-merger/ili23/replace/data.xtf create mode 100644 src/test/data/xtf-merger/ili23/replace/expected.xtf create mode 100644 src/test/data/xtf-merger/ili23/replace/patch.xtf create mode 100644 src/test/data/xtf-merger/ili24/replace/data.xtf create mode 100644 src/test/data/xtf-merger/ili24/replace/expected.xtf create mode 100644 src/test/data/xtf-merger/ili24/replace/patch.xtf diff --git a/src/test/data/xtf-merger/ili23/replace/data.xtf b/src/test/data/xtf-merger/ili23/replace/data.xtf new file mode 100644 index 0000000..e4b3c4a --- /dev/null +++ b/src/test/data/xtf-merger/ili23/replace/data.xtf @@ -0,0 +1,22 @@ + + + + + + + + + + Some text + Some more text + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/data/xtf-merger/ili23/replace/expected.xtf b/src/test/data/xtf-merger/ili23/replace/expected.xtf new file mode 100644 index 0000000..54126e8 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/replace/expected.xtf @@ -0,0 +1,23 @@ + + + + + + + + + + Some text + Some more text + + + + + + Replaced Value + + New attribute + + + + diff --git a/src/test/data/xtf-merger/ili23/replace/patch.xtf b/src/test/data/xtf-merger/ili23/replace/patch.xtf new file mode 100644 index 0000000..aedbfc9 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/replace/patch.xtf @@ -0,0 +1,12 @@ + + + + + + Replaced Value + + New attribute + + + + diff --git a/src/test/data/xtf-merger/ili24/replace/data.xtf b/src/test/data/xtf-merger/ili24/replace/data.xtf new file mode 100644 index 0000000..308412e --- /dev/null +++ b/src/test/data/xtf-merger/ili24/replace/data.xtf @@ -0,0 +1,23 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/data/xtf-merger/ili24/replace/expected.xtf b/src/test/data/xtf-merger/ili24/replace/expected.xtf new file mode 100644 index 0000000..5de0dbb --- /dev/null +++ b/src/test/data/xtf-merger/ili24/replace/expected.xtf @@ -0,0 +1,24 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + + + + Replaced Value + + New attribute + + + + diff --git a/src/test/data/xtf-merger/ili24/replace/patch.xtf b/src/test/data/xtf-merger/ili24/replace/patch.xtf new file mode 100644 index 0000000..8595c3d --- /dev/null +++ b/src/test/data/xtf-merger/ili24/replace/patch.xtf @@ -0,0 +1,12 @@ + + + + + + Replaced Value + + New attribute + + + + diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java index 6fce7dd..f139be6 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -39,6 +39,12 @@ public void addElements(String iliVersion) throws IOException { mergeAndValidateXtf(Path.of(DATA_BASE_PATH, iliVersion, "add")); } + @ParameterizedTest + @ValueSource(strings = {"ili23", "ili24"}) + public void replaceElements(String iliVersion) throws IOException { + mergeAndValidateXtf(Path.of(DATA_BASE_PATH, iliVersion, "replace")); + } + @ParameterizedTest @ValueSource(strings = {"ili23", "ili24"}) public void combinedOperations(String iliVersion) throws IOException { From 2bf0a746fb0f188e77cc2d8908cc72bc71eadb08 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Mon, 11 Dec 2023 10:47:14 +0100 Subject: [PATCH 8/8] Use delete attribute to remove elements from xtf --- .../interlis/testbed/runner/xtf/Basket.java | 25 +++++++++++++++- .../testbed/runner/xtf/XtfFileMerger.java | 30 +++++++++++++++---- .../xtf-merger/ili23/combined/expected.xtf | 4 --- .../data/xtf-merger/ili23/combined/patch.xtf | 4 +++ .../data/xtf-merger/ili23/delete/data.xtf | 26 ++++++++++++++++ .../data/xtf-merger/ili23/delete/expected.xtf | 15 ++++++++++ .../data/xtf-merger/ili23/delete/patch.xtf | 9 ++++++ .../xtf-merger/ili24/combined/expected.xtf | 4 --- .../data/xtf-merger/ili24/combined/patch.xtf | 4 +++ .../data/xtf-merger/ili24/delete/data.xtf | 27 +++++++++++++++++ .../data/xtf-merger/ili24/delete/expected.xtf | 16 ++++++++++ .../data/xtf-merger/ili24/delete/patch.xtf | 9 ++++++ .../testbed/runner/xtf/XtfFileMergerTest.java | 8 ++++- 13 files changed, 166 insertions(+), 15 deletions(-) create mode 100644 src/test/data/xtf-merger/ili23/delete/data.xtf create mode 100644 src/test/data/xtf-merger/ili23/delete/expected.xtf create mode 100644 src/test/data/xtf-merger/ili23/delete/patch.xtf create mode 100644 src/test/data/xtf-merger/ili24/delete/data.xtf create mode 100644 src/test/data/xtf-merger/ili24/delete/expected.xtf create mode 100644 src/test/data/xtf-merger/ili24/delete/patch.xtf diff --git a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java index 2aa4f08..713487b 100644 --- a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java +++ b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/Basket.java @@ -12,7 +12,7 @@ public record Basket(Element element, Map objects) { * @param entryId the entry ID * @param node the node to add or replace */ - public void addOrReplaceChild(String entryId, Node node) { + public void addOrReplaceChildNode(String entryId, Node node) { var originalEntry = objects().get(entryId); if (originalEntry == null) { element().appendChild(node); @@ -20,4 +20,27 @@ public void addOrReplaceChild(String entryId, Node node) { element().replaceChild(node, originalEntry); } } + + /** + * Removes the basket node from the XML document. + */ + public void removeBasketNode() { + element().getParentNode().removeChild(element()); + } + + /** + * Removes the child node with the given entry ID. + * + * @param entryId the ID of the entry to remove + * @return {@code true} if the entry was removed, {@code false} if the entry was not found + */ + public boolean removeChildNode(String entryId) { + var originalEntry = objects().get(entryId); + if (originalEntry == null) { + return false; + } + + element().removeChild(originalEntry); + return true; + } } diff --git a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java index 35f122e..95018a8 100644 --- a/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java +++ b/src/main/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMerger.java @@ -26,6 +26,8 @@ public final class XtfFileMerger implements XtfMerger { private static final Logger LOGGER = LogManager.getLogger(); private static final String BASKET_ID = "BID"; private static final String OBJECT_ID = "TID"; + private static final String DELETE_ATTRIBUTE = "DELETE"; + private static final String DELETE_ATTRIBUTE_LOWERCASE = DELETE_ATTRIBUTE.toLowerCase(); private static final String INTERLIS24_NAMESPACE = "http://www.interlis.ch/xtf/2.4/INTERLIS"; private final DocumentBuilderFactory factory; @@ -79,8 +81,9 @@ DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { private static boolean mergeBaskets(Document document, Map baseBaskets, Map patchBaskets) { var isValid = true; - for (var patchBasket : patchBaskets.entrySet()) { - var basketId = patchBasket.getKey(); + for (var patchBasketEntry : patchBaskets.entrySet()) { + var basketId = patchBasketEntry.getKey(); + var patchBasket = patchBasketEntry.getValue(); var originalBasket = baseBaskets.get(basketId); if (originalBasket == null) { @@ -89,11 +92,24 @@ private static boolean mergeBaskets(Document document, Map baseB continue; } - for (var patchEntry : patchBasket.getValue().objects().entrySet()) { + if (hasDeleteAttribute(patchBasket.element())) { + originalBasket.removeBasketNode(); + continue; + } + + for (var patchEntry : patchBasket.objects().entrySet()) { var entryId = patchEntry.getKey(); + var element = patchEntry.getValue(); - var importedNode = document.importNode(patchEntry.getValue(), true); - originalBasket.addOrReplaceChild(entryId, importedNode); + if (hasDeleteAttribute(element)) { + if (!originalBasket.removeChildNode(entryId)) { + LOGGER.error("Could not remove entry " + entryId + " from basket " + basketId + " as it does not exist."); + isValid = false; + } + } else { + var importedNode = document.importNode(element, true); + originalBasket.addOrReplaceChildNode(entryId, importedNode); + } } } @@ -141,6 +157,10 @@ private static Basket collectBasket(Element basket) { return new Basket(basket, objects); } + private static boolean hasDeleteAttribute(Element element) { + return element.hasAttribute(DELETE_ATTRIBUTE) || element.hasAttribute(DELETE_ATTRIBUTE_LOWERCASE); + } + private static boolean hasInterlisAttribute(Element element, String attributeName) { return getInterlisAttribute(element, attributeName) != null; } diff --git a/src/test/data/xtf-merger/ili23/combined/expected.xtf b/src/test/data/xtf-merger/ili23/combined/expected.xtf index 0ab6b78..a86bf89 100644 --- a/src/test/data/xtf-merger/ili23/combined/expected.xtf +++ b/src/test/data/xtf-merger/ili23/combined/expected.xtf @@ -45,10 +45,6 @@ - - Some text - Some more text - diff --git a/src/test/data/xtf-merger/ili23/combined/patch.xtf b/src/test/data/xtf-merger/ili23/combined/patch.xtf index c88cd9f..7ce5439 100644 --- a/src/test/data/xtf-merger/ili23/combined/patch.xtf +++ b/src/test/data/xtf-merger/ili23/combined/patch.xtf @@ -23,5 +23,9 @@ Attr2 + + + + diff --git a/src/test/data/xtf-merger/ili23/delete/data.xtf b/src/test/data/xtf-merger/ili23/delete/data.xtf new file mode 100644 index 0000000..999c589 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/delete/data.xtf @@ -0,0 +1,26 @@ + + + + + + + + + + Some text + Some more text + + + Attribute 1 + Attribute 2 + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/data/xtf-merger/ili23/delete/expected.xtf b/src/test/data/xtf-merger/ili23/delete/expected.xtf new file mode 100644 index 0000000..08f1555 --- /dev/null +++ b/src/test/data/xtf-merger/ili23/delete/expected.xtf @@ -0,0 +1,15 @@ + + + + + + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/ili23/delete/patch.xtf b/src/test/data/xtf-merger/ili23/delete/patch.xtf new file mode 100644 index 0000000..500eb0b --- /dev/null +++ b/src/test/data/xtf-merger/ili23/delete/patch.xtf @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/data/xtf-merger/ili24/combined/expected.xtf b/src/test/data/xtf-merger/ili24/combined/expected.xtf index 9510658..64efa27 100644 --- a/src/test/data/xtf-merger/ili24/combined/expected.xtf +++ b/src/test/data/xtf-merger/ili24/combined/expected.xtf @@ -46,10 +46,6 @@ - - Some text - Some more text - diff --git a/src/test/data/xtf-merger/ili24/combined/patch.xtf b/src/test/data/xtf-merger/ili24/combined/patch.xtf index 6648570..00e0884 100644 --- a/src/test/data/xtf-merger/ili24/combined/patch.xtf +++ b/src/test/data/xtf-merger/ili24/combined/patch.xtf @@ -23,5 +23,9 @@ Attr2 + + + + diff --git a/src/test/data/xtf-merger/ili24/delete/data.xtf b/src/test/data/xtf-merger/ili24/delete/data.xtf new file mode 100644 index 0000000..684f786 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/delete/data.xtf @@ -0,0 +1,27 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + Attribute 1 + Attribute 2 + + + + + + Attribute 1 + Attribute 2 + + + + diff --git a/src/test/data/xtf-merger/ili24/delete/expected.xtf b/src/test/data/xtf-merger/ili24/delete/expected.xtf new file mode 100644 index 0000000..ae15d7c --- /dev/null +++ b/src/test/data/xtf-merger/ili24/delete/expected.xtf @@ -0,0 +1,16 @@ + + + + + + interlis-testbed-runner + + + + + Some text + Some more text + + + + diff --git a/src/test/data/xtf-merger/ili24/delete/patch.xtf b/src/test/data/xtf-merger/ili24/delete/patch.xtf new file mode 100644 index 0000000..d1ebc63 --- /dev/null +++ b/src/test/data/xtf-merger/ili24/delete/patch.xtf @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java index f139be6..349dbd2 100644 --- a/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java +++ b/src/test/java/ch/geowerkstatt/interlis/testbed/runner/xtf/XtfFileMergerTest.java @@ -45,6 +45,12 @@ public void replaceElements(String iliVersion) throws IOException { mergeAndValidateXtf(Path.of(DATA_BASE_PATH, iliVersion, "replace")); } + @ParameterizedTest + @ValueSource(strings = {"ili23", "ili24"}) + public void deleteElements(String iliVersion) throws IOException { + mergeAndValidateXtf(Path.of(DATA_BASE_PATH, iliVersion, "delete")); + } + @ParameterizedTest @ValueSource(strings = {"ili23", "ili24"}) public void combinedOperations(String iliVersion) throws IOException { @@ -73,7 +79,7 @@ private void assertEqualXtfFiles(Path expectedFile, Path actualFile) throws IOEx var expectedXml = Files.readString(expectedFile); var actualXml = Files.readString(actualFile); - var nodeMatcher = new DefaultNodeMatcher(ElementSelectors.byNameAndText); + var nodeMatcher = new DefaultNodeMatcher(ElementSelectors.byName); var diff = DiffBuilder .compare(expectedXml) .withTest(actualXml)