Skip to content

Commit

Permalink
Test Resources Cleanup, XmlHandler Improve, Unit Tests (#4)
Browse files Browse the repository at this point in the history
* Test Resources Cleanup, XmlHandler Improve, Unit Tests

- Added getNodeFromXPath, for single Node retrieval.
- Deleted test_resource_2.xml
- Adapted test_resource_1.xml
- Added more unit tests to XmlHandlerTest.java
- .editorconfig updated

* CHANGELOG.md Updated, README.md Updated

* maven.yml Updated

* maven.yml Updated
  • Loading branch information
rikkarth authored Dec 1, 2023
1 parent 4cd760d commit 4f7032d
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 67 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ indent_size = 4
# Ignore some files and directories
[**.md]
max_line_length = 120

[*.xml]
indent_style = tab
tab_width = 4
22 changes: 20 additions & 2 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ name: Java CI with Maven

on:
push:
branches: [ "main" ]
branches: [ "main", "dev" ]
pull_request:
branches: [ "main" ]
branches: [ "main", "dev" ]

jobs:

Expand Down Expand Up @@ -45,3 +45,21 @@ jobs:
cache: maven
- name: Build with Maven
run: mvn -B package --file pom.xml

create_tag:

runs-on: ubuntu-latest

needs: build

if: github.ref == 'refs/heads/main'

steps:
- name: Get version from pom.xml
run: echo "##[set-output name=version]$(xmllint --xpath 'string(/project/version)' pom.xml)"
id: get_version
- name: Create tag
run: |
echo "Creating tag v${{ steps.get_version.outputs.version }}"
git tag -a v${{ steps.get_version.outputs.version }} -m "Release v${{ steps.get_version.outputs.version }}"
git push origin v${{ steps.get_version.outputs.version }}
11 changes: 6 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [0.0.3] - 01-12-2023

### Changed

- **XmlHandler** now handles XPathExpressions internally, getStringFromXPath and getNodeListFromXPath both now only
require the expression to be provided as a String instead of an XPathExpression object.

### Added

- CHANGELOG.md
- **Installed**: Maven Wrapper
- **Installed**: JUnit Params
- Ability to retrieve single Node from XPath with XmlHandler.

### Changed

- **XmlHandler** now handles XPathExpressions internally, getStringFromXPath and getNodeListFromXPath both now only
require the expression to be provided as a String instead of an XPathExpression object.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

## [0.0.3] - 01-12-2023

### Changed

- **XmlHandler** now handles XPathExpressions internally, getStringFromXPath and getNodeListFromXPath both now only
require the expression to be provided as a String instead of an XPathExpression object.

### Added

- CHANGELOG.md
- **Installed**: Maven Wrapper
- **Installed**: JUnit Params
- Ability to retrieve single Node from XPath with XmlHandler.

### Changed

- **XmlHandler** now handles XPathExpressions internally, getStringFromXPath and getNodeListFromXPath both now only
require the expression to be provided as a String instead of an XPathExpression object.

# Tooler-Tools

Expand Down
27 changes: 26 additions & 1 deletion src/main/java/org/toolertools/xml/XmlHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Expand All @@ -13,6 +14,7 @@
import javax.xml.xpath.XPathFactory;
import org.toolertools.internal.DocConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

Expand All @@ -36,13 +38,36 @@ public static String getStringFromXPath(String expression, Document document) {
public static NodeList getNodeListFromXPath(String expression, Document document) {
try {
XPathExpression xPathExpression = createXPathExpression(expression);
return (NodeList) xPathExpression.evaluate(document, XPathConstants.NODESET);
return Objects.requireNonNull((NodeList) xPathExpression.evaluate(document, XPathConstants.NODESET));
} catch (XPathExpressionException | NullPointerException e) {
Document doc = createEmptyDocument();
return doc.createDocumentFragment().getChildNodes();
}
}

public static Node getNodeFromXPath(String expression, Document document) {
try {
XPathExpression xPathExpression = createXPathExpression(expression);
return Objects.requireNonNull((Node) xPathExpression.evaluate(document, XPathConstants.NODE));
} catch (XPathExpressionException | NullPointerException e) {
Document doc = createEmptyDocument();
return doc.createElement("null");
}
}

public static Node getNodeFromXPath(String expression, Document document, boolean onErrorReturnNull) {
try {
XPathExpression xPathExpression = createXPathExpression(expression);
return Objects.requireNonNull((Node) xPathExpression.evaluate(document, XPathConstants.NODE));
} catch (XPathExpressionException | NullPointerException e) {
if (onErrorReturnNull) {
return null;
}
Document doc = createEmptyDocument();
return doc.createElement("null");
}
}

public static Optional<Document> getOptionalDomFromFile(final File file) {
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
Expand Down
111 changes: 87 additions & 24 deletions src/test/java/org/toolertools/xml/XmlHandlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,134 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

class XmlHandlerTest {

private static final String ELEMENT_1_X_PATH = "/root/element1/text()";
private static final String EMPTY_ELEMENT_X_PATH = "/root/emptyElement/text()";
private static final String COMPLIANT_X_PATH = ELEMENT_1_X_PATH;
private static final String MALFORMED_X_PATH = "/root/element1/tet()";
private static final String TEST_ELEMENT_TEXT = "//test-element/text()";
private static final String NESTED_ELEMENT_TEXT = "//nested-element/text()";
private static final String EMPTY_ELEMENT_TEXT = "//empty-element/text()";
private static final String SELF_CLOSING_TEXT = "//self-closing/text()";
private static final String ELEMENT_GROUP_TEXT = "//element-group/text()";
private static final String ELEMENT_GROUP_NODE = "//element-group";
private static final String COMPLIANT_X_PATH = TEST_ELEMENT_TEXT;
private static final String MALFORMED_X_PATH = "/root/malformed/text()";

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void testGetStringFromXPath_success(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

String element1 = XmlHandler.getStringFromXPath(ELEMENT_1_X_PATH, doc);
String emptyElement = XmlHandler.getStringFromXPath(EMPTY_ELEMENT_X_PATH, doc);
String testElement = XmlHandler.getStringFromXPath(TEST_ELEMENT_TEXT, doc);
String nestedElement = XmlHandler.getStringFromXPath(NESTED_ELEMENT_TEXT, doc);

assertFalse(element1.isEmpty(), ELEMENT_1_X_PATH + " should not be empty");
assertTrue(emptyElement.isEmpty(), EMPTY_ELEMENT_X_PATH + " should be empty");
String emptyElement = XmlHandler.getStringFromXPath(EMPTY_ELEMENT_TEXT, doc);
String selfClosing = XmlHandler.getStringFromXPath(SELF_CLOSING_TEXT, doc);
String elementGroup = XmlHandler.getStringFromXPath(ELEMENT_GROUP_TEXT, doc);

assertPresentElements(testElement, nestedElement, elementGroup);

assertEmptyElements(emptyElement, selfClosing);
}

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void givenBadValues_getStringFromXPath_shouldReturnEmptyString(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

String element1 = XmlHandler.getStringFromXPath(ELEMENT_1_X_PATH, null);
String emptyElement = XmlHandler.getStringFromXPath(EMPTY_ELEMENT_X_PATH, null);
String testElement = XmlHandler.getStringFromXPath(TEST_ELEMENT_TEXT, null);
String emptyElement = XmlHandler.getStringFromXPath(EMPTY_ELEMENT_TEXT, null);
String malformed = XmlHandler.getStringFromXPath(MALFORMED_X_PATH, doc);
String malformed2 = XmlHandler.getStringFromXPath(null, doc);
String nullExpressionCase = XmlHandler.getStringFromXPath(null, doc);

assertTrue(element1.isEmpty(), ELEMENT_1_X_PATH + " should be empty");
assertTrue(emptyElement.isEmpty(), EMPTY_ELEMENT_X_PATH + "should be empty");
assertTrue(malformed.isEmpty(), MALFORMED_X_PATH + "should be empty");
assertTrue(malformed2.isEmpty(), "provided null expression should be empty");
assertEmptyElements(testElement, emptyElement, malformed, nullExpressionCase);
}

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void givenCompliantValues_testNodeList_success(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

NodeList nlCompliant = XmlHandler.getNodeListFromXPath(COMPLIANT_X_PATH, doc);
NodeList elementGroup = XmlHandler.getNodeListFromXPath(NESTED_ELEMENT_TEXT, doc);

assertEquals(1, nlCompliant.getLength(), "NodeList should be size 1");
assertEquals(3, elementGroup.getLength(), "NodeList should be size 3");
}

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void givenBadValues_testNodeList_failure(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

NodeList nlBad = XmlHandler.getNodeListFromXPath(COMPLIANT_X_PATH, null);
NodeList nlBad2 = XmlHandler.getNodeListFromXPath(MALFORMED_X_PATH, doc);
NodeList nlBad3 = XmlHandler.getNodeListFromXPath(null, doc);
NodeList nullDocumentCase = XmlHandler.getNodeListFromXPath(COMPLIANT_X_PATH, null);
NodeList malformedXPathCase = XmlHandler.getNodeListFromXPath(MALFORMED_X_PATH, doc);
NodeList nullXPathcase = XmlHandler.getNodeListFromXPath(null, doc);

assertEmptyNodeLists(nullDocumentCase, malformedXPathCase, nullXPathcase);
}

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void givenCompliantValues_testGetNodeFromXPath_success(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

Node groupElement = XmlHandler.getNodeFromXPath(ELEMENT_GROUP_NODE, doc);

assertEquals(Document.ELEMENT_NODE, groupElement.getNodeType(), "Should be element node");
assertEquals("element-group", groupElement.getNodeName(), "Should be element node");
}

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void givenBadValues_testGetNodeFromXPath_failure(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

Node groupElement = XmlHandler.getNodeFromXPath(MALFORMED_X_PATH, doc);
Node groupElementNullExpression = XmlHandler.getNodeFromXPath(null, doc);
Node groupElementNullDoc = XmlHandler.getNodeFromXPath(MALFORMED_X_PATH, null);

assertNotNullNodes(groupElement, groupElementNullExpression, groupElementNullDoc);

assertNodeNameNull(groupElement, groupElementNullExpression, groupElementNullDoc);
}

@ParameterizedTest
@ValueSource(strings = "src/test/resources/test_resource_1.xml")
void givenBadValues_testGetNodeFromXPathOverloaded_failure(String input) {
Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new);

Node groupElement = XmlHandler.getNodeFromXPath(MALFORMED_X_PATH, doc, true);

assertNull(groupElement, "Should be null");
}

private static void assertEmptyElements(String... strings) {
Arrays.stream(strings).forEach(string -> assertTrue(string.isEmpty(), "Should be empty"));
}

private static void assertPresentElements(String... strings) {
Arrays.stream(strings).forEach(string -> assertFalse(string.isEmpty(), "Should not be empty"));
}

private static void assertEmptyNodeLists(NodeList... strings) {
Arrays.stream(strings)
.forEach(nodeList -> assertEquals(0, nodeList.getLength(), "NodeList should be be size 0"));
}

private static void assertNotNullNodes(Node... nodes) {
Arrays.stream(nodes).forEach(node -> assertNotNull(node, "Should not be null"));
}

assertEquals(0, nlBad.getLength(), "NodeList should be be size 0");
assertEquals(0, nlBad2.getLength(), "NodeList should be be size 0");
assertEquals(0, nlBad3.getLength(), "NodeList should be be size 0");
private static void assertNodeNameNull(Node... nodes) {
Arrays.stream(nodes).forEach(node -> assertEquals("null", node.getNodeName(), "Node name should be 'null'"));
}
}
21 changes: 9 additions & 12 deletions src/test/resources/test_resource_1.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<element1>Value 1</element1>
<element2>Value 2</element2>
<emptyElement></emptyElement>
<nestedElement>
<subElement>SubValue</subElement>
</nestedElement>
<elements>
<element>Item 1</element>
<element>Item 2</element>
<element>Item 3</element>
</elements>
<root xmlns="http://example.com/test">
<test-element>Test Value</test-element>
<empty-element></empty-element>
<self-closing/>
<element-group>
<nested-element>Item 1</nested-element>
<nested-element>Item 2</nested-element>
<nested-element>Item 3</nested-element>
</element-group>
</root>
18 changes: 0 additions & 18 deletions src/test/resources/test_resource_2.xml

This file was deleted.

0 comments on commit 4f7032d

Please sign in to comment.