All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.amygdalum.testrecorder.runtime.MapMatcher Maven / Gradle / Ivy

The newest version!
package net.amygdalum.testrecorder.runtime;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNull.nullValue;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import org.hamcrest.TypeSafeMatcher;
import org.hamcrest.core.IsNull;

public class MapMatcher extends TypeSafeMatcher> {

    private Class key;
    private Class value;
    private Map, Matcher> entries;

    public MapMatcher(Class key, Class value) {
        this.key = key;
        this.value = value;
        this.entries = new LinkedHashMap<>();
    }

    public MapMatcher entry(K key, V value) {
        return entry(matchKey(key), matchValue(value));
    }

    public MapMatcher entry(Matcher key, V value) {
        return entry(key, matchValue(value));
    }

    public MapMatcher entry(K key, Matcher value) {
        return entry(matchKey(key), value);
    }

    @SuppressWarnings("unchecked")
    public MapMatcher entry(Matcher key, Matcher value) {
        entries.put((Matcher) key, (Matcher) value);
        return this;
    }

    @SuppressWarnings("unchecked")
    private Matcher matchKey(K element) {
        if (element == null) {
            return nullValue(key);
        } else if (element instanceof Matcher) {
            return (Matcher) element;
        } else {
            return equalTo(element);
        }
    }

    @SuppressWarnings("unchecked")
    private Matcher matchValue(V element) {
        if (element == null) {
            return nullValue(value);
        } else if (element instanceof Matcher) {
            return (Matcher) element;
        } else {
            return equalTo(element);
        }
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("containing ").appendValueList("{", ", ", "}", entries.entrySet());
    }

    @Override
    protected void describeMismatchSafely(Map item, Description mismatchDescription) {
        List, Matcher>> unmatched = new LinkedList<>(entries.entrySet());
        List> notfound = new LinkedList<>();

        for (Entry entry : item.entrySet()) {

            boolean success = tryMatch(unmatched, entry);
            if (!success) {
                notfound.add(new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue()));
            }
        }

        if (!unmatched.isEmpty()) {
            mismatchDescription.appendText("missing entries ").appendValueList("{", ", ", "}", unmatched);
        }
        if (!unmatched.isEmpty() && !notfound.isEmpty()) {
            mismatchDescription.appendText(", ");
        }
        if (!notfound.isEmpty()) {
            mismatchDescription.appendText("unmatched entries ").appendValueList("{", ", ", "}", toDescriptionMap(notfound));
        }
    }

    private Collection> toDescriptionMap(List> entries) {
        Matcher keyMatcher = bestKeyMatcher();
        Matcher valueMatcher = bestValueMatcher();
        Map map = new LinkedHashMap<>();
        for (Entry entry : entries) {
            String key = descriptionOf(keyMatcher, entry.getKey());
            String value = descriptionOf(valueMatcher, entry.getValue());
            map.put(key, value);
        }
        return map.entrySet();
    }

    private Matcher bestValueMatcher() {
        for (Matcher matcher : entries.values()) {
            if (matcher.getClass() != IsNull.class) {
                return matcher;
            }
        }
        return equalTo(null);
    }

    private Matcher bestKeyMatcher() {
        for (Matcher matcher : entries.keySet()) {
            if (matcher.getClass() != IsNull.class) {
                return matcher;
            }
        }
        return equalTo(null);
    }

    private  String descriptionOf(Matcher valueMatcher, T value) {
        StringDescription description = new StringDescription();
        valueMatcher.describeMismatch(value, description);
        return description.toString();
    }

    @Override
    protected boolean matchesSafely(Map item) {
        List, Matcher>> unmatched = new LinkedList<>(entries.entrySet());

        for (Entry entry : item.entrySet()) {

            boolean success = tryMatch(unmatched, entry);
            if (!success) {
                return false;
            }
        }

        return unmatched.isEmpty();
    }

    private boolean tryMatch(List, Matcher>> unmatched, Entry entry) {
        K key = entry.getKey();
        V value = entry.getValue();

        Iterator, Matcher>> matchers = unmatched.iterator();
        while (matchers.hasNext()) {
            Entry, Matcher> matcher = matchers.next();
            if (matcher.getKey().matches(key) && matcher.getValue().matches(value)) {
                matchers.remove();
                return true;
            }
        }
        return false;
    }

    public static  MapMatcher noEntries(Class key, Class value) {
        return new MapMatcher<>(key, value);
    }

    public static  MapMatcher containsEntries(Class key, Class value) {
        return new MapMatcher<>(key, value);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
	public static MapMatcher noEntries() {
        return new MapMatcher(Object.class, Object.class);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static MapMatcher containsEntries() {
        return new MapMatcher(Object.class, Object.class);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy