From f51d34c91e7c690a30a5909c5544458fa2f6448e Mon Sep 17 00:00:00 2001
From: Mykola Dzyuba <7852483+mdzyuba@users.noreply.github.com>
Date: Wed, 7 Jan 2026 14:30:03 -0800
Subject: [PATCH] Add integration tests for all formatter options
Integration tests that verify XML formatting by comparing input files
against expected output files for each tool option:
Test cases:
- Default options (id, layout_width, layout_height first)
- Custom indentation (--indention)
- Custom attribute indentation (--attribute-indention)
- Custom attribute order (--attribute-order)
- Alphabetical attribute sort (--attribute-sort)
- Custom namespace order (--namespace-order)
- Alphabetical namespace sort (--namespace-sort)
- Combined options (multiple flags together)
- Zero indentation
- Valid XML output verification
- Nested element structure verification
---
pom.xml | 6 +
.../androidxmlformatter/IntegrationTest.java | 298 ++++++++++++++++++
.../integration/attribute_sort_expected.xml | 8 +
.../integration/attribute_sort_input.xml | 7 +
.../integration/combined_options_expected.xml | 9 +
.../integration/combined_options_input.xml | 8 +
.../custom_attribute_indention_expected.xml | 7 +
.../custom_attribute_indention_input.xml | 6 +
.../custom_attribute_order_expected.xml | 8 +
.../custom_attribute_order_input.xml | 7 +
.../integration/custom_indention_expected.xml | 14 +
.../integration/custom_indention_input.xml | 13 +
.../custom_namespace_order_expected.xml | 8 +
.../custom_namespace_order_input.xml | 7 +
.../integration/default_options_expected.xml | 22 ++
.../integration/default_options_input.xml | 21 ++
.../integration/namespace_sort_expected.xml | 8 +
.../integration/namespace_sort_input.xml | 7 +
18 files changed, 464 insertions(+)
create mode 100644 src/test/java/com/bytehamster/androidxmlformatter/IntegrationTest.java
create mode 100644 src/test/resources/integration/attribute_sort_expected.xml
create mode 100644 src/test/resources/integration/attribute_sort_input.xml
create mode 100644 src/test/resources/integration/combined_options_expected.xml
create mode 100644 src/test/resources/integration/combined_options_input.xml
create mode 100644 src/test/resources/integration/custom_attribute_indention_expected.xml
create mode 100644 src/test/resources/integration/custom_attribute_indention_input.xml
create mode 100644 src/test/resources/integration/custom_attribute_order_expected.xml
create mode 100644 src/test/resources/integration/custom_attribute_order_input.xml
create mode 100644 src/test/resources/integration/custom_indention_expected.xml
create mode 100644 src/test/resources/integration/custom_indention_input.xml
create mode 100644 src/test/resources/integration/custom_namespace_order_expected.xml
create mode 100644 src/test/resources/integration/custom_namespace_order_input.xml
create mode 100644 src/test/resources/integration/default_options_expected.xml
create mode 100644 src/test/resources/integration/default_options_input.xml
create mode 100644 src/test/resources/integration/namespace_sort_expected.xml
create mode 100644 src/test/resources/integration/namespace_sort_input.xml
diff --git a/pom.xml b/pom.xml
index 2b712b9..21b0b71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,6 +29,12 @@
jdom
1.1.3
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.2
+ test
+
diff --git a/src/test/java/com/bytehamster/androidxmlformatter/IntegrationTest.java b/src/test/java/com/bytehamster/androidxmlformatter/IntegrationTest.java
new file mode 100644
index 0000000..7359f0a
--- /dev/null
+++ b/src/test/java/com/bytehamster/androidxmlformatter/IntegrationTest.java
@@ -0,0 +1,298 @@
+package com.bytehamster.androidxmlformatter;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.jdom.Document;
+import org.jdom.input.SAXBuilder;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Integration tests that verify XML formatting with various options by comparing input XML files
+ * against expected output XML files.
+ */
+class IntegrationTest {
+
+ private static final String INTEGRATION_DIR = "/integration/";
+ private static final String INPUT_SUFFIX = "_input.xml";
+ private static final String EXPECTED_SUFFIX = "_expected.xml";
+
+ private String loadResource(String path) throws Exception {
+ try (InputStream is = getClass().getResourceAsStream(path)) {
+ if (is == null) {
+ throw new IllegalArgumentException("Resource not found: " + path);
+ }
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int bytesRead;
+ byte[] data = new byte[1024];
+ while ((bytesRead = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, bytesRead);
+ }
+ return new String(buffer.toByteArray(), StandardCharsets.UTF_8);
+ }
+ }
+
+ private Document parseResource(String path) throws Exception {
+ try (InputStream is = getClass().getResourceAsStream(path)) {
+ if (is == null) {
+ throw new IllegalArgumentException("Resource not found: " + path);
+ }
+ return new SAXBuilder().build(is);
+ }
+ }
+
+ private String formatDocument(AndroidXmlOutputter outputter, Document doc) throws Exception {
+ StringWriter writer = new StringWriter();
+ outputter.output(doc, writer);
+ return writer.toString();
+ }
+
+ private void assertFormattedOutputMatches(
+ String testName,
+ int indention,
+ int attributeIndention,
+ String[] namespaceOrder,
+ String[] attributeOrder,
+ boolean attributeSort,
+ boolean namespaceSort)
+ throws Exception {
+
+ Document inputDoc = parseResource(INTEGRATION_DIR + testName + INPUT_SUFFIX);
+ String expected = loadResource(INTEGRATION_DIR + testName + EXPECTED_SUFFIX);
+
+ AndroidXmlOutputter outputter = new AndroidXmlOutputter(
+ indention,
+ attributeIndention,
+ namespaceOrder,
+ attributeOrder,
+ attributeSort,
+ namespaceSort);
+
+ String actual = formatDocument(outputter, inputDoc);
+
+ // Normalize line endings for comparison
+ expected = expected.replace("\r\n", "\n").trim();
+ actual = actual.replace("\r\n", "\n").trim();
+
+ assertEquals(expected, actual, "Formatted output should match expected for: " + testName);
+ }
+
+ // === Default Options Test ===
+
+ @Test
+ @DisplayName("Default options: id, layout_width, layout_height first with 4-space indentation")
+ void testDefaultOptions() throws Exception {
+ assertFormattedOutputMatches(
+ "default_options",
+ 4, // indention
+ 4, // attribute indention
+ new String[] { "android" }, // namespace order
+ new String[] { "id", "layout_width", "layout_height" }, // attribute order
+ false, // attribute sort
+ false // namespace sort
+ );
+ }
+
+ // === Custom Indentation Test ===
+
+ @Test
+ @DisplayName("Custom indentation: 2 spaces instead of 4")
+ void testCustomIndention() throws Exception {
+ assertFormattedOutputMatches(
+ "custom_indention",
+ 2, // indention
+ 2, // attribute indention
+ new String[] { "android" }, // namespace order
+ new String[] { "id", "layout_width", "layout_height" }, // attribute order
+ false, // attribute sort
+ false // namespace sort
+ );
+ }
+
+ // === Custom Attribute Indentation Test ===
+
+ @Test
+ @DisplayName("Custom attribute indentation: 8 spaces for attributes")
+ void testCustomAttributeIndention() throws Exception {
+ assertFormattedOutputMatches(
+ "custom_attribute_indention",
+ 4, // indention
+ 8, // attribute indention
+ new String[] { "android" }, // namespace order
+ new String[] { "id", "layout_width", "layout_height" }, // attribute order
+ false, // attribute sort
+ false // namespace sort
+ );
+ }
+
+ // === Custom Attribute Order Test ===
+
+ @Test
+ @DisplayName("Custom attribute order: text, background first")
+ void testCustomAttributeOrder() throws Exception {
+ assertFormattedOutputMatches(
+ "custom_attribute_order",
+ 4, // indention
+ 4, // attribute indention
+ new String[] { "android" }, // namespace order
+ new String[] { "text", "background" }, // attribute order
+ false, // attribute sort
+ false // namespace sort
+ );
+ }
+
+ // === Alphabetical Attribute Sort Test ===
+
+ @Test
+ @DisplayName("Attribute sort: alphabetical ordering of attributes")
+ void testAttributeSort() throws Exception {
+ assertFormattedOutputMatches(
+ "attribute_sort",
+ 4, // indention
+ 4, // attribute indention
+ new String[] { "android" }, // namespace order
+ new String[] {}, // attribute order (empty for pure alphabetical)
+ true, // attribute sort
+ false // namespace sort
+ );
+ }
+
+ // === Custom Namespace Order Test ===
+
+ @Test
+ @DisplayName("Custom namespace order: tools, app, android")
+ void testCustomNamespaceOrder() throws Exception {
+ assertFormattedOutputMatches(
+ "custom_namespace_order",
+ 4, // indention
+ 4, // attribute indention
+ new String[] { "tools", "app", "android" }, // namespace order
+ new String[] { "id", "layout_width", "layout_height" }, // attribute order
+ false, // attribute sort
+ false // namespace sort
+ );
+ }
+
+ // === Alphabetical Namespace Sort Test ===
+
+ @Test
+ @DisplayName("Namespace sort: alphabetical ordering of namespaces")
+ void testNamespaceSort() throws Exception {
+ assertFormattedOutputMatches(
+ "namespace_sort",
+ 4, // indention
+ 4, // attribute indention
+ new String[] {}, // namespace order (empty for pure alphabetical)
+ new String[] { "id", "layout_width", "layout_height" }, // attribute order
+ false, // attribute sort
+ true // namespace sort
+ );
+ }
+
+ // === Combined Options Test ===
+
+ @Test
+ @DisplayName("Combined options: 2-space indent, 6-space attr indent, both sorts enabled")
+ void testCombinedOptions() throws Exception {
+ assertFormattedOutputMatches(
+ "combined_options",
+ 2, // indention
+ 6, // attribute indention
+ new String[] {}, // namespace order (empty for alphabetical)
+ new String[] {}, // attribute order (empty for alphabetical)
+ true, // attribute sort
+ true // namespace sort
+ );
+ }
+
+ // === Additional Integration Tests ===
+
+ @Test
+ @DisplayName("Zero indentation: no indentation for elements or attributes")
+ void testZeroIndentation() throws Exception {
+ Document inputDoc = parseResource(INTEGRATION_DIR + "default_options" + INPUT_SUFFIX);
+
+ AndroidXmlOutputter outputter = new AndroidXmlOutputter(
+ 0,
+ 0,
+ new String[] { "android" },
+ new String[] { "id", "layout_width", "layout_height" },
+ false,
+ false);
+
+ String result = formatDocument(outputter, inputDoc);
+
+ // With zero indentation, child elements should not be indented
+ assertTrue(result.contains("