/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.test.matcher;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.core.AllOf;
/**
* Matchers that examine the contents of a {@link Map}.
* <p>
* It is possible to match a single entry by value or matcher like this:
* </p>
*
* <pre class="code">
* assertThat(map, hasEntry(SOME_KEY, is(SOME_VALUE)));
* assertThat(map, hasEntry(SOME_KEY, is(String.class)));
* assertThat(map, hasEntry(SOME_KEY, notNullValue()));
* </pre>
*
* <p>
* It's also possible to match multiple entries in a map:
* </p>
*
* <pre class="code">
* {@code
* Map<String, Object> expectedInMap = new HashMap<String, Object>();
* expectedInMap.put(SOME_KEY, SOME_VALUE);
* expectedInMap.put(OTHER_KEY, is(OTHER_VALUE));
* assertThat(map, hasAllEntries(expectedInMap));
* }
* </pre>
*
* <p>If you only need to verify the existence of a key:</p>
*
* <pre class="code">
* assertThat(map, hasKey(SOME_KEY));
* </pre>
*
* @author Alex Peters
* @author Iwein Fuld
* @author Gunnar Hillert
* @author Artem Bilan
*
*/
public class MapContentMatchers<T, V> extends
TypeSafeMatcher<Map<? super T, ? super V>> {
private final T key;
private final Matcher<V> valueMatcher;
private MapContentMatchers(T key, V value) {
this(key, Matchers.equalTo(value));
}
private MapContentMatchers(T key, Matcher<V> valueMatcher) {
this.key = key;
this.valueMatcher = valueMatcher;
}
@Override
public boolean matchesSafely(Map<? super T, ? super V> item) {
return item.containsKey(key) && valueMatcher.matches(item.get(key));
}
@Override
public void describeTo(Description description) {
description.appendText("an entry with key ").appendValue(key)
.appendText(" and value matching ").appendDescriptionOf(
valueMatcher);
}
@Factory
public static <T, V> Matcher<Map<? super T, ? super V>> hasEntry(T key, V value) {
return new MapContentMatchers<>(key, value);
}
@Factory
public static <T, V> Matcher<Map<? super T, ? super V>> hasEntry(T key, Matcher<V> valueMatcher) {
return new MapContentMatchers<>(key, valueMatcher);
}
@Factory
@SuppressWarnings("unchecked")
public static <T, V> Matcher<Map<? super T, ? super V>> hasKey(T key) {
return new MapContentMatchers<>(key, (Matcher<V>) Matchers.anything());
}
@Factory
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T, V> Matcher<Map<? super T, ? super V>> hasAllEntries(Map<T, V> entries) {
List<Matcher<Map<? super T, ? super V>>> matchers = new ArrayList<>(entries.size());
for (Map.Entry<T, V> entry : entries.entrySet()) {
final V value = entry.getValue();
if (value instanceof Matcher<?>) {
matchers.add(hasEntry(entry.getKey(), (Matcher<V>) value));
}
else {
matchers.add(hasEntry(entry.getKey(), value));
}
}
//return AllOf.allOf(matchers); //Does not work with Hamcrest 1.3
return new AllOf(matchers);
}
}