package org.test4j.hamcrest.matcher.property.reflection; import java.util.IdentityHashMap; import java.util.Map; import org.test4j.hamcrest.matcher.property.difference.ClassDifference; import org.test4j.hamcrest.matcher.property.difference.CollectionDifference; import org.test4j.hamcrest.matcher.property.difference.Difference; import org.test4j.hamcrest.matcher.property.difference.DifferenceVisitor; import org.test4j.hamcrest.matcher.property.difference.MapDifference; import org.test4j.hamcrest.matcher.property.difference.ObjectDifference; import org.test4j.hamcrest.matcher.property.difference.UnorderedCollectionDifference; /** * A utility class to be able to calculate a score of how well 2 elements match. * This enables us to find the best matching differences out of all element * differences in an unordered collection difference. */ public class MatchingScoreCalculator { /** * The visitor for visiting the difference tree */ protected MatchingScoreVisitor matchingScoreVisitor = new MatchingScoreVisitor(); /** * Cache for matching scores */ protected Map<Difference, Integer> cachedMatchingScores = new IdentityHashMap<Difference, Integer>(); /** * Gets the matching score for the given difference. * * @param difference * The difference * @return The score */ public int calculateMatchingScore(Difference difference) { if (difference == null) { return 0; } Integer matchingScore = cachedMatchingScores.get(difference); if (matchingScore == null) { matchingScore = difference.accept(matchingScoreVisitor, null); cachedMatchingScores.put(difference, matchingScore); } return matchingScore; } /** * Gets the matching score for a simple difference. This will return 0 in * case both objects are of the same type. If both objects are of a * different type, they are less likely to be a best match, so 5 is * returned. * * @param difference * The difference, not null * @return The score */ protected int getMatchingScore(Difference difference) { Object leftValue = difference.getLeftValue(); Object rightValue = difference.getRightValue(); if (leftValue != null && rightValue != null && !leftValue.getClass().equals(rightValue.getClass())) { return 5; } return 1; } /** * Gets the matching score for an object difference. Returns the nr of field * differences. * * @param objectDifference * The difference, not null * @return The score */ protected int getMatchingScore(ObjectDifference objectDifference) { return objectDifference.getFieldDifferences().size(); } /** * Gets the matching score for a map difference. Returns the nr of value * differences. * * @param mapDifference * The difference, not null * @return The score */ protected int getMatchingScore(MapDifference mapDifference) { return mapDifference.getValueDifferences().size(); } /** * Gets the matching score for a collection difference. Returns the nr of * element differences. * * @param collectionDifference * The difference, not null * @return The score */ protected int getMatchingScore(CollectionDifference collectionDifference) { return collectionDifference.getElementDifferences().size(); } /** * Gets the matching score for an unordered collection difference. Returns * the sum of the matching scores of the best matches. * * @param unorderedCollectionDifference * The difference, not null * @return The score */ protected int getMatchingScore(UnorderedCollectionDifference unorderedCollectionDifference) { return unorderedCollectionDifference.getBestMatchingScore(); } /** * The visitor for visiting the difference tree. */ protected class MatchingScoreVisitor implements DifferenceVisitor<Integer, Integer> { public Integer visit(Difference difference, Integer argument) { return getMatchingScore(difference); } public Integer visit(ObjectDifference objectDifference, Integer argument) { return getMatchingScore(objectDifference); } public Integer visit(ClassDifference classDifference, Integer argument) { return getMatchingScore(classDifference); } public Integer visit(MapDifference mapDifference, Integer argument) { return getMatchingScore(mapDifference); } public Integer visit(CollectionDifference collectionDifference, Integer argument) { return getMatchingScore(collectionDifference); } public Integer visit(UnorderedCollectionDifference unorderedCollectionDifference, Integer argument) { return getMatchingScore(unorderedCollectionDifference); } } }