Skip to content

Commit

Permalink
Added a few nice assertiosn.
Browse files Browse the repository at this point in the history
  • Loading branch information
mihxil committed Jan 9, 2025
1 parent 6d79a4b commit 53a27a6
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 28 deletions.
24 changes: 24 additions & 0 deletions vpro-shared-test/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
= Test related utilities
:toc:

== Assertj

- xml related assertions
- json related assertions
- serialization related assertions

== Testcontainers

(optional dependencies)

- postgresql
- elasticsearch

== Jupiter/Junit5

Some extension like

- AbortOnException
- DoAfterException
- TestMDC
- TimingExtension
145 changes: 117 additions & 28 deletions vpro-shared-test/src/main/java/nl/vpro/test/util/jaxb/JAXBTestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
*/
package nl.vpro.test.util.jaxb;

import jakarta.xml.bind.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.function.Supplier;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
Expand All @@ -26,13 +25,17 @@
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import jakarta.xml.bind.*;
import jakarta.xml.bind.annotation.XmlRootElement;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.StringBuilderWriter;
import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.Fail;
import org.w3c.dom.Element;
import org.w3c.dom.*;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.*;
import org.xmlunit.XMLUnitException;
import org.xmlunit.builder.DiffBuilder;
Expand All @@ -49,6 +52,7 @@
* @author Roelof Jan Koekoek
* @since 1.6
*/
@Slf4j
public class JAXBTestUtil {

private static final String LOCAL_URI = "uri:local";
Expand All @@ -61,7 +65,6 @@ public static <T> String marshal(T object) {
marshal(object, (o) -> JAXB.marshal(o, writer));
return writer.toString();
}

public static <T> Element marshalToElement(T object) {
DOMResult writer = new DOMResult();
marshal(object, (o) -> JAXB.marshal(o, writer));
Expand Down Expand Up @@ -133,15 +136,12 @@ public static <T> T roundTrip(T input, String contains) {
return (T)JAXB.unmarshal(new StringReader(xml), input.getClass());
}

/**
* Checks whether the
*
* @since 2.7
*/
@SuppressWarnings("unchecked")

@SneakyThrows
public static <T> T roundTripContains(T input, boolean namespaceAware, String... contains) {
@SuppressWarnings("unchecked")
public static <T> Result<T> roundTripAndSimilarResult(T input, boolean namespaceAware, String... contains) {
Element xml = marshalToElement(input);

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
DocumentBuilder builder = factory.newDocumentBuilder();
Expand All @@ -153,7 +153,7 @@ public static <T> T roundTripContains(T input, boolean namespaceAware, String..
} catch (SAXException | IOException se) {
throw new RuntimeException(se);
}
}).collect(Collectors.toList());
}).toList();
for (Element elementToFind : elementsToFind) {
NodeList elementsByTagName = xml.getElementsByTagName(elementToFind.getTagName());
boolean found = false;
Expand All @@ -176,8 +176,34 @@ public static <T> T roundTripContains(T input, boolean namespaceAware, String..
assertThat(writer.toString()).contains(contains);
}
}
return (T)JAXB.unmarshal(new DOMSource(xml), input.getClass());


return new Result<>((T)JAXB.unmarshal(new DOMSource(xml), input.getClass()), () -> {
String str;
try {
DOMImplementationLS lsImpl = (DOMImplementationLS) xml.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
LSSerializer serializer = lsImpl.createLSSerializer();
serializer.getDomConfig().setParameter("xml-declaration", false);
str = serializer.writeToString(xml);
} catch (Exception e){
log.warn(e.getMessage());
str = marshal(input);
}
return str;
});
}

/**
* Checks whether the
*
* @since 2.7
*/

public static <T> T roundTripContains(T input, boolean namespaceAware, String... contains) {
return roundTripAndSimilarResult(input, namespaceAware, contains).rounded();
}


/**
* Checks whether marshalled version of an object contains a certain piece of xml.
*
Expand All @@ -187,6 +213,11 @@ public static <T> T roundTripContains(T input, String... contains) {
return roundTripContains(input, true, contains);
}

public static <T> Result<T> roundTripContainsResult(T input, String... contains) {
return roundTripAndSimilarResult(input, true, contains);
}



@SafeVarargs
public static <T> T roundTripAndSimilar(String input, Class<? extends T> inputClazz, Consumer<DiffBuilder>... build) {
Expand All @@ -207,16 +238,24 @@ public static <T> T roundTripAndSimilar(InputStream input, Class<? extends T> in
* Marshalls input and checks if it is similar to given string.
* Then unmarshals it, and marshalls it another time. The result XMl should still be similar.
*/
@SuppressWarnings({"DuplicatedCode", "unchecked"})
@SuppressWarnings({"DuplicatedCode"})
public static <T> T roundTripAndSimilar(T input, String expected) {
return roundTripAndSimilarResult(input, expected).rounded();
}

/**
* @since 5.4
*/
@SuppressWarnings({"DuplicatedCode", "unchecked"})
public static <T> Result<T> roundTripAndSimilarResult(T input, String expected) {
String xml = marshal(input);
similar(xml, expected);
Class<? extends T> clazz = (Class<? extends T>) input.getClass();
T result = unmarshal(xml, clazz);
/// make sure unmarshalling worked too, by marshalling the result again.
String xmlAfter = marshal(result);
similar(xmlAfter, xml);
return result;
return new Result<>(result, xml);
}

public static <T> T roundTripAndValidateAndSimilar(T input, URL xsd, InputStream expected) throws IOException, SAXException {
Expand Down Expand Up @@ -250,13 +289,16 @@ public static <T> T roundTripAndValidateAndSimilar(T input, URL xsd, String expe
}
}
public static <T> T roundTripAndSimilar(T input, InputStream expected) throws IOException {

StringWriter writer = new StringWriter();
IOUtils.copy(expected, writer, UTF_8);
return roundTripAndSimilar(input, writer.toString());
}


public static <T> Result<T> roundTripAndSimilarResult(T input, InputStream expected) throws IOException {
StringWriter writer = new StringWriter();
IOUtils.copy(expected, writer, UTF_8);
return roundTripAndSimilarResult(input, writer.toString());
}


public static <T> T roundTripAndSimilarAndEquals(T input, String expected) {
Expand Down Expand Up @@ -340,7 +382,7 @@ public static <S extends JAXBTestUtil.XMLObjectAssert<S, T>, T> XMLObjectAssert<
return new XMLObjectAssert<>(o);
}

public static JAXBTestUtil.XMLStringAssert assertThatXml(String o) {
public static JAXBTestUtil.XMLStringAssert assertThatXml(CharSequence o) {
return new XMLStringAssert(o);
}

Expand All @@ -359,6 +401,8 @@ public static class XMLObjectAssert<S extends XMLObjectAssert<S, A>, A> extends

A rounded;

String xml;

boolean roundTrip = true;


Expand All @@ -375,12 +419,15 @@ protected XMLObjectAssert(A actual) {
public S isSimilarTo(String expected) {
if (roundTrip) {
try {
rounded = roundTripAndSimilar(actual, expected);

Result<A> result = roundTripAndSimilarResult(actual, expected);
rounded = result.rounded();
xml = result.xml();
} catch (Exception e) {
Fail.fail(e.getMessage(), e);
}
} else {
String xml = marshal(actual);
xml = marshal(actual);
similar(xml, expected);
}
return myself;
Expand All @@ -393,12 +440,15 @@ public S isSimilarTo(String expected) {
public S isSimilarTo(InputStream expected) {
if (roundTrip) {
try {
rounded = roundTripAndSimilar(actual, expected);

Result<A> result = roundTripAndSimilarResult(actual, expected);
rounded = result.rounded();
xml = result.xml();
} catch (Exception e) {
Fail.fail(e.getMessage(), e);
}
} else {
String xml = marshal(actual);
xml = marshal(actual);
similar(xml, expected);
}
return myself;
Expand All @@ -408,33 +458,56 @@ public S isSimilarTo(InputStream expected) {
@SuppressWarnings({"CatchMayIgnoreException"})
public S containsSimilar(String expected) {
try {
rounded = roundTripContains(actual, expected);
Result<A> result = roundTripContainsResult(actual, expected);
rounded = result.rounded;
xml = result.xml();
} catch (Exception e) {
Fail.fail(e.getMessage(), e);
}
return myself;

}

/**
* As {@code assertThat(}{@link #get()}{@code )}
*/
public AbstractObjectAssert<?, A> andRounded() {
if (rounded == null) {
throw new IllegalStateException("No similation was done already.");
}
return assertThat(rounded);
return assertThat(get());
}

public S isValid (javax.xml.validation.Validator validator) throws SAXException, IOException {
validator.validate(new StreamSource(new StringReader(marshal(rounded))));
return myself;
}

/**
* Returns the object as it is after marshalling/unmarshalling
* @return The object after a round trip
*
*/
public A get() {
if (rounded == null) {
throw new IllegalStateException("No similation was done already.");
}
return rounded;
}

/**
* Returns the object as it is after marshalling/unmarshalling
* @return The object after a round trip
*
*/
public String xml() {
if (xml == null) {
throw new IllegalStateException("No marshalling was done already.");
}
return xml;
}

public Result<A> getResult() {
return new Result(rounded, xml);
}


}

public static class XMLStringAssert extends AbstractObjectAssert<XMLStringAssert, CharSequence> {
Expand All @@ -457,6 +530,22 @@ public XMLStringAssert isSimilarTo(InputStream expected) {
}
}

/**
* @since 5.4
*/
public record Result<A>(A rounded, Supplier<String> xmlSupplier) {

public Result(A rounded, String xml) {
this(rounded, () -> xml);
}

public String xml() {
return xmlSupplier.get();
}

}


protected static void assertNoDifferences(Diff diff, byte[] input, byte[] expected) {
if (diff.hasDifferences()) {
assertThat(pretty(input)).isEqualTo(pretty(expected));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ public void testContainsNoNamespaceFails() {
}).isInstanceOf(AssertionError.class);
}

@Test
public void testContainsFluentResult() {
Result<A> result = assertThatXml(new A()).containsSimilar("""
<b xmlns="urn:test:1234" i='1' j='2'>
<value>bb</value>
<c>cc</c>
</b>""").getResult();
assertThat(result.rounded().getB().getJ()).isEqualTo(2);
assertThatXml(result.xml()).isSimilarTo("""
<a xmlns="urn:test:1234"><value>aa</value><b i="1" j="2"><value>bb</value><c>cc</c></b></a>
""");
}

@Test
public void testContainsFluent() {
A rounded = assertThatXml(new A()).containsSimilar("""
Expand Down

0 comments on commit 53a27a6

Please sign in to comment.