SimilarHtmlPattern.java

package fr.sii.ogham.testing.assertion.wiremock;

import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.matching.MatchResult;
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
import fr.sii.ogham.testing.assertion.exception.ComparisonException;
import fr.sii.ogham.testing.assertion.util.HtmlUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xmlunit.diff.Diff;

import java.util.concurrent.atomic.AtomicInteger;

import static com.github.tomakehurst.wiremock.matching.MatchResult.*;

/**
 * Check if the HTML is similar to the expected. The HTML strings are parsed
 * into {@link Document}s. Two documents are considered to be "similar" if they
 * contain the same elements and attributes regardless of order.
 * 
 * <p>
 * See {@link HtmlUtils} for more information about "similar" HTML.
 * 
 * <p>
 * NOTE: {@link WireMock#equalToXml(String)} does an identical check.
 * 
 * @author Aurélien Baudet
 *
 */
public class SimilarHtmlPattern extends StringValuePattern {
	private static final Logger LOG = LoggerFactory.getLogger(SimilarHtmlPattern.class);

	/**
	 * Initialized with the expected HTML
	 *
	 * @param expectedValue
	 *            the expected HTML
	 */
	public SimilarHtmlPattern(@wiremock.com.fasterxml.jackson.annotation.JsonProperty("similarHtml") String expectedValue) {
		super(expectedValue);
	}

	@Override
	public MatchResult match(String value) {
		try {
			Diff diff = HtmlUtils.compare(expectedValue, value, false);
			return diff.hasDifferences() ? partialMatch(computeDistance(diff)) : exactMatch();
		} catch(ComparisonException e) {
			// ignore because WireMock will try each value (body, multipart files, ...) so comparison may fail
			// due to not xml value
			LOG.debug("Can't match since ", e);
			return noMatch();
		}
	}

	private double computeDistance(Diff diff) {
		final AtomicInteger count = new AtomicInteger();
		diff.getDifferences().forEach((d) -> count.incrementAndGet());
		return count.doubleValue();
	}
}