package org.infernus.idea.checkstyle.service;
import java.util.Arrays;
import java.util.Objects;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.Configuration;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.jetbrains.annotations.NotNull;
public class ConfigurationMatcher extends TypeSafeMatcher<Configuration> {
private static final int INDENT_SIZE = 2;
private final Configuration expected;
public ConfigurationMatcher(final Configuration expected) {
this.expected = expected;
}
public static Matcher<? super Configuration> configEqualTo(final Configuration expected) {
return new ConfigurationMatcher(expected);
}
protected boolean matchesSafely(final Configuration actual) {
return equals(actual, expected);
}
private boolean equals(Configuration config1, Configuration config2) {
if (config1 == config2) {
return true;
}
if (config1 == null
|| !Objects.equals(config1.getName(), config2.getName())
|| config1.getChildren().length != config2.getChildren().length
|| !Arrays.equals(config1.getAttributeNames(), config2.getAttributeNames())
|| childrenAreNotEqual(config1, config2)
|| attributesAreNotEqual(config1, config2)
|| messagesAreNotEqual(config1, config2)) {
return false;
}
return true;
}
private boolean messagesAreNotEqual(final Configuration config1, final Configuration config2) {
return !Objects.equals(config1.getMessages(), config2.getMessages());
}
private boolean attributesAreNotEqual(final Configuration config1, final Configuration config2) {
for (String attributeName : config1.getAttributeNames()) {
if (!Objects.equals(attrValue(config1, attributeName), attrValue(config2, attributeName))) {
return true;
}
}
return false;
}
private boolean childrenAreNotEqual(final Configuration config1, final Configuration config2) {
final Configuration[] sortedConfig1Children = sortedChildrenOf(config1);
final Configuration[] sortedConfig2Children = sortedChildrenOf(config2);
for (int i = 0; i < sortedConfig1Children.length; ++i) {
if (!equals(sortedConfig1Children[i], sortedConfig2Children[i])) {
return true;
}
}
return false;
}
@NotNull
private Configuration[] sortedChildrenOf(final Configuration config1) {
final Configuration[] sortedConfigChildren = config1.getChildren();
Arrays.sort(sortedConfigChildren, (a, b) -> a.getName().compareTo(b.getName()));
return sortedConfigChildren;
}
@Override
public void describeTo(final Description description) {
description
.appendText("equal to\n")
.appendText(toString(expected, 1));
}
@Override
protected void describeMismatchSafely(final Configuration actual, final Description mismatchDescription) {
mismatchDescription
.appendText("was\n")
.appendText(toString(actual, 1));
}
private String toString(final Configuration configuration, final int indentLevel) {
final StringBuilder out = new StringBuilder();
out.append(indent(indentLevel)).append("<module name=\"").append(configuration.getName()).append("\"");
for (String attrName : configuration.getAttributeNames()) {
out.append(" ").append(attrName).append("=\"").append(attrValue(configuration, attrName)).append("\"");
}
if (configuration.getChildren().length > 0) {
out.append(">\n");
for (Configuration child : configuration.getChildren()) {
out.append(toString(child, indentLevel + 1));
}
out.append(indent(indentLevel)).append("</module>\n");
} else {
out.append("/>\n");
}
return out.toString();
}
private String attrValue(final Configuration configuration, final String attributeName) {
try {
return configuration.getAttribute(attributeName);
} catch (CheckstyleException e) {
return "";
}
}
private String indent(final int level) {
final StringBuilder out = new StringBuilder();
for (int i = 0; i < level * INDENT_SIZE; ++i) {
out.append(" ");
}
return out.toString();
}
}