aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-01-02 15:17:50 +0000
committerMichael Williamson <mike@zwobble.org>2016-01-02 15:18:22 +0000
commitd5005305b90afe47e639fc0fa1430242556f0385 (patch)
tree387c8e888b925917da79e1ad829e14665c7b8cc6 /src/test
parent70edd90a3077fc63a5890c4d7d55561ba0274902 (diff)
Add possibly ill-advised DeepReflectionMatcher
Diffstat (limited to 'src/test')
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/DeepReflectionMatcher.java136
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java39
2 files changed, 159 insertions, 16 deletions
diff --git a/src/test/java/org/zwobble/mammoth/tests/DeepReflectionMatcher.java b/src/test/java/org/zwobble/mammoth/tests/DeepReflectionMatcher.java
new file mode 100644
index 0000000..8ee0d8f
--- /dev/null
+++ b/src/test/java/org/zwobble/mammoth/tests/DeepReflectionMatcher.java
@@ -0,0 +1,136 @@
+package org.zwobble.mammoth.tests;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static java.util.Arrays.asList;
+
+public class DeepReflectionMatcher<T> extends TypeSafeDiagnosingMatcher<T> {
+ private final T expected;
+
+ public DeepReflectionMatcher(T expected) {
+ this.expected = expected;
+ }
+
+ @Override
+ protected boolean matchesSafely(T item, Description mismatchDescription) {
+ return matchesSafely("", expected, item, mismatchDescription);
+ }
+
+ private static <T> boolean matchesSafely(String path, T expected, T actual, Description mismatchDescription) {
+ if (expected instanceof List && actual instanceof List) {
+ return matchesList(path, (List)expected, (List)actual, mismatchDescription);
+ }
+
+ if (!expected.getClass().equals(actual.getClass())) {
+ mismatchDescription.appendText("was " + actual.getClass().getName());
+ return false;
+ }
+
+ if (expected instanceof String) {
+ return matchesString(path, expected, actual, mismatchDescription);
+ }
+
+ for (Field field : fields(expected.getClass())) {
+ if (!matchesSafely(path + "." + field.getName(), readField(expected, field), readField(actual, field), mismatchDescription)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static <T> boolean matchesList(String path, List<?> expected, List<?> actual, Description mismatchDescription) {
+ if (actual.size() > expected.size()) {
+ appendPath(mismatchDescription, path);
+ mismatchDescription.appendText("extra elements:" +
+ indentedList(transform(Iterables.skip(actual, expected.size()), DeepReflectionMatcher::generateDescriptionOfValue)));
+ return false;
+ }
+
+ if (actual.size() < expected.size()) {
+ appendPath(mismatchDescription, path);
+ mismatchDescription.appendText("missing elements:" +
+ indentedList(transform(Iterables.skip(expected, actual.size()), DeepReflectionMatcher::generateDescriptionOfValue)));
+ return false;
+ }
+
+ for (int index = 0; index < expected.size(); index++) {
+ if (!matchesSafely(path + "[" + index + "]", expected.get(index), actual.get(index), mismatchDescription)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static <T> boolean matchesString(String path, T expected, T actual, Description mismatchDescription) {
+ Matcher<Object> matcher = Matchers.equalTo(expected);
+ if (!matcher.matches(actual)) {
+ appendPath(mismatchDescription, path);
+ matcher.describeMismatch(actual, mismatchDescription);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private static void appendPath(Description mismatchDescription, String path) {
+ mismatchDescription.appendText(path + ": ");
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(generateDescriptionOfValue(expected));
+ }
+
+ private static String generateDescriptionOfValue(Object value) {
+ if (value instanceof String) {
+ return value.toString();
+ } else if (value instanceof List) {
+ List<?> list = (List)value;
+ return "[" + indentedList(transform(list, DeepReflectionMatcher::generateDescriptionOfValue)) + "]";
+ } else {
+ Class<?> clazz = value.getClass();
+ List<Field> fields = fields(clazz);
+ Iterable<String> fieldStrings = transform(
+ fields,
+ field -> field.getName() + "=" + generateDescriptionOfValue(readField(value, field)));
+ return String.format("%s(%s)", clazz.getSimpleName(), indentedList(fieldStrings));
+ }
+ }
+
+ private static String indentedList(Iterable<String> values) {
+ return Joiner.on(",").join(transform(values, value -> "\n " + indent(value)));
+ }
+
+ private static String indent(String value) {
+ return value.replaceAll("\n", "\n ");
+ }
+
+ private static ImmutableList<Field> fields(Class<?> clazz) {
+ return ImmutableList.copyOf(filter(
+ asList(clazz.getDeclaredFields()),
+ field -> !Modifier.isStatic(field.getModifiers())));
+ }
+
+ private static Object readField(Object obj, Field field) {
+ try {
+ field.setAccessible(true);
+ return field.get(obj);
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+}
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
index 8ab2dd8..e2ee5a9 100644
--- a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
@@ -7,16 +7,17 @@ import org.zwobble.mammoth.documents.DocumentElement;
import org.zwobble.mammoth.documents.ParagraphElement;
import org.zwobble.mammoth.documents.RunElement;
import org.zwobble.mammoth.documents.TextElement;
+import org.zwobble.mammoth.tests.DeepReflectionMatcher;
import org.zwobble.mammoth.xml.XmlElement;
import org.zwobble.mammoth.xml.XmlNode;
+import org.zwobble.mammoth.xml.XmlNodes;
import java.util.List;
+import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
import static org.zwobble.mammoth.docx.BodyXml.readBodyXmlElement;
import static org.zwobble.mammoth.xml.XmlNodes.element;
-import static org.zwobble.mammoth.xml.XmlNodes.text;
public class BodyXmlTests {
@Test
@@ -30,7 +31,7 @@ public class BodyXmlTests {
XmlElement element = runXml(ImmutableList.of(textXml("Hello!")));
assertThat(
readBodyXmlElement(element),
- isRunElement(isTextElement("Hello!")));
+ isRun(run(text("Hello!"))));
}
@Test
@@ -38,7 +39,7 @@ public class BodyXmlTests {
XmlElement element = paragraphXml(ImmutableList.of(runXml(ImmutableList.of(textXml("Hello!")))));
assertThat(
readBodyXmlElement(element),
- isParagraphElement(isRunElement(isTextElement("Hello!"))));
+ isParagraph(paragraph(run(text("Hello!")))));
}
private XmlElement paragraphXml(List<XmlNode> children) {
@@ -50,24 +51,30 @@ public class BodyXmlTests {
}
private XmlElement textXml(String value) {
- return element("w:t", ImmutableList.of(text(value)));
+ return element("w:t", ImmutableList.of(XmlNodes.text(value)));
}
- private Matcher<DocumentElement> isParagraphElement(Matcher<DocumentElement> child) {
- return allOf(
- instanceOf(ParagraphElement.class),
- hasProperty("children", contains(child)));
+ private Matcher<DocumentElement> isParagraph(ParagraphElement expected) {
+ return new DeepReflectionMatcher<>(expected);
}
- private Matcher<DocumentElement> isRunElement(Matcher<DocumentElement> child) {
- return allOf(
- instanceOf(RunElement.class),
- hasProperty("children", contains(child)));
+ private Matcher<DocumentElement> isRun(RunElement expected) {
+ return new DeepReflectionMatcher<>(expected);
}
private Matcher<DocumentElement> isTextElement(String value) {
- return allOf(
- instanceOf(TextElement.class),
- hasProperty("value", equalTo(value)));
+ return new DeepReflectionMatcher<>(new TextElement(value));
+ }
+
+ private ParagraphElement paragraph(DocumentElement... children) {
+ return new ParagraphElement(asList(children));
+ }
+
+ private RunElement run(DocumentElement... children) {
+ return new RunElement(asList(children));
+ }
+
+ private TextElement text(String value) {
+ return new TextElement(value);
}
}