/*
* Copyright (C) 2015 Google Inc.
*
* 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 com.google.cloud.dataflow.sdk.testing;
import com.google.cloud.dataflow.sdk.coders.Coder;
import com.google.cloud.dataflow.sdk.coders.CoderException;
import com.google.cloud.dataflow.sdk.coders.ListCoder;
import com.google.cloud.dataflow.sdk.util.CoderUtils;
import com.google.cloud.dataflow.sdk.util.UserCodeException;
import com.google.cloud.dataflow.sdk.values.KV;
import com.google.common.base.MoreObjects;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
/**
* Static class for building and using {@link SerializableMatcher} instances.
*
* Most matchers are wrappers for hamcrest's {@link Matchers}. Please be familiar with the
* documentation there. Values retained by a {@link SerializableMatcher} are required to be
* serializable, either via Java serialization or via a provided {@link Coder}.
*
*
The following matchers are novel to Dataflow:
*
* {@link #kvWithKey} for matching just the key of a {@link KV}.
* {@link #kvWithValue} for matching just the value of a {@link KV}.
* {@link #kv} for matching the key and value of a {@link KV}.
*
*
* For example, to match a group from
* {@link com.google.cloud.dataflow.sdk.transforms.GroupByKey}, which has type
* {@code KV>} for some {@code K} and {@code V} and where the order of the iterable
* is undefined, use a matcher like
* {@code kv(equalTo("some key"), containsInAnyOrder(1, 2, 3))}.
*/
class SerializableMatchers implements Serializable {
// Serializable only because of capture by anonymous inner classes
private SerializableMatchers() { } // not instantiable
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#allOf(Iterable)}.
*/
public static SerializableMatcher
allOf(Iterable> serializableMatchers) {
@SuppressWarnings({"rawtypes", "unchecked"}) // safe covariant cast
final Iterable> matchers = (Iterable) serializableMatchers;
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.allOf(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#allOf(Matcher[])}.
*/
@SafeVarargs
public static SerializableMatcher allOf(final SerializableMatcher... matchers) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.allOf(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#anyOf(Iterable)}.
*/
public static SerializableMatcher
anyOf(Iterable> serializableMatchers) {
@SuppressWarnings({"rawtypes", "unchecked"}) // safe covariant cast
final Iterable> matchers = (Iterable) serializableMatchers;
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.anyOf(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#anyOf(Matcher[])}.
*/
@SafeVarargs
public static SerializableMatcher anyOf(final SerializableMatcher... matchers) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.anyOf(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#anything()}.
*/
public static SerializableMatcher anything() {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.anything();
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContaining(Object[])}.
*/
@SafeVarargs
public static SerializableMatcher
arrayContaining(final T... items) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContaining(items);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContaining(Object[])}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}. They are
* explicitly not required or expected to be serializable via Java serialization.
*/
@SafeVarargs
public static SerializableMatcher arrayContaining(Coder coder, T... items) {
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContaining(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContaining(Matcher[])}.
*/
@SafeVarargs
public static SerializableMatcher
arrayContaining(final SerializableMatcher... matchers) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContaining(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContaining(List)}.
*/
public static SerializableMatcher
arrayContaining(List> serializableMatchers) {
@SuppressWarnings({"rawtypes", "unchecked"}) // safe covariant cast
final List> matchers = (List) serializableMatchers;
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContaining(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContainingInAnyOrder(Object[])}.
*/
@SafeVarargs
public static SerializableMatcher
arrayContainingInAnyOrder(final T... items) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContainingInAnyOrder(items);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContainingInAnyOrder(Object[])}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}. They are
* explicitly not required or expected to be serializable via Java serialization.
*/
@SafeVarargs
public static SerializableMatcher arrayContainingInAnyOrder(Coder coder, T... items) {
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContaining(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContainingInAnyOrder(Matcher[])}.
*/
@SafeVarargs
public static SerializableMatcher arrayContainingInAnyOrder(
final SerializableMatcher... matchers) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContainingInAnyOrder(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayContainingInAnyOrder(Collection)}.
*/
public static SerializableMatcher arrayContainingInAnyOrder(
Collection> serializableMatchers) {
@SuppressWarnings({"rawtypes", "unchecked"}) // safe covariant cast
final Collection> matchers = (Collection) serializableMatchers;
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayContainingInAnyOrder(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayWithSize(int)}.
*/
public static SerializableMatcher arrayWithSize(final int size) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayWithSize(size);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#arrayWithSize(Matcher)}.
*/
public static SerializableMatcher arrayWithSize(
final SerializableMatcher sizeMatcher) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.arrayWithSize(sizeMatcher);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#closeTo(double,double)}.
*/
public static SerializableMatcher closeTo(final double target, final double error) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.closeTo(target, error);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#contains(Object[])}.
*/
@SafeVarargs
public static SerializableMatcher> contains(
final T... items) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.contains(items);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#contains(Object[])}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}. They are
* explicitly not required or expected to be serializable via Java serialization.
*/
@SafeVarargs
public static SerializableMatcher>
contains(Coder coder, T... items) {
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.containsInAnyOrder(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#contains(Matcher[])}.
*/
@SafeVarargs
public static SerializableMatcher> contains(
final SerializableMatcher... matchers) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.contains(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#contains(List)}.
*/
public static SerializableMatcher> contains(
List> serializableMatchers) {
@SuppressWarnings({"rawtypes", "unchecked"}) // safe covariant cast
final List> matchers = (List) serializableMatchers;
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.contains(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#containsInAnyOrder(Object[])}.
*/
@SafeVarargs
public static SerializableMatcher>
containsInAnyOrder(final T... items) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.containsInAnyOrder(items);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#containsInAnyOrder(Object[])}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}.
* It is explicitly not required or expected to be serializable via Java serialization.
*/
@SafeVarargs
public static SerializableMatcher>
containsInAnyOrder(Coder coder, T... items) {
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.containsInAnyOrder(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#containsInAnyOrder(Matcher[])}.
*/
@SafeVarargs
public static SerializableMatcher> containsInAnyOrder(
final SerializableMatcher... matchers) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.containsInAnyOrder(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#containsInAnyOrder(Collection)}.
*/
public static SerializableMatcher> containsInAnyOrder(
Collection> serializableMatchers) {
@SuppressWarnings({"rawtypes", "unchecked"}) // safe covariant cast
final Collection> matchers = (Collection) serializableMatchers;
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.containsInAnyOrder(matchers);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#containsString}.
*/
public static SerializableMatcher containsString(final String substring) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.containsString(substring);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#empty()}.
*/
public static SerializableMatcher> empty() {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.empty();
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#emptyArray()}.
*/
public static SerializableMatcher emptyArray() {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.emptyArray();
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#emptyIterable()}.
*/
public static SerializableMatcher> emptyIterable() {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.emptyIterable();
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#endsWith}.
*/
public static SerializableMatcher endsWith(final String substring) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.endsWith(substring);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#equalTo()}.
*/
public static SerializableMatcher equalTo(final T expected) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.equalTo(expected);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#equalTo()}.
*
* The expected value of type {@code T} will be serialized using the provided {@link Coder}.
* It is explicitly not required or expected to be serializable via Java serialization.
*/
public static SerializableMatcher equalTo(Coder coder, T expected) {
final SerializableSupplier expectedSupplier = new SerializableViaCoder<>(coder, expected);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.equalTo(expectedSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#greaterThan()}.
*/
public static & Serializable> SerializableMatcher
greaterThan(final T target) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.greaterThan(target);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#greaterThan()}.
*
* The target value of type {@code T} will be serialized using the provided {@link Coder}.
* It is explicitly not required or expected to be serializable via Java serialization.
*/
public static & Serializable> SerializableMatcher
greaterThan(final Coder coder, T target) {
final SerializableSupplier targetSupplier = new SerializableViaCoder<>(coder, target);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.greaterThan(targetSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#greaterThanOrEqualTo()}.
*/
public static > SerializableMatcher greaterThanOrEqualTo(
final T target) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.greaterThanOrEqualTo(target);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#greaterThanOrEqualTo()}.
*
* The target value of type {@code T} will be serialized using the provided {@link Coder}.
* It is explicitly not required or expected to be serializable via Java serialization.
*/
public static & Serializable> SerializableMatcher
greaterThanOrEqualTo(final Coder coder, T target) {
final SerializableSupplier targetSupplier = new SerializableViaCoder<>(coder, target);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.greaterThanOrEqualTo(targetSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#hasItem(Object)}.
*/
public static SerializableMatcher> hasItem(
final T target) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.hasItem(target);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#hasItem(Object)}.
*
* The item of type {@code T} will be serialized using the provided {@link Coder}.
* It is explicitly not required or expected to be serializable via Java serialization.
*/
public static SerializableMatcher> hasItem(Coder coder, T target) {
final SerializableSupplier targetSupplier = new SerializableViaCoder<>(coder, target);
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.hasItem(targetSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#hasItem(Matcher)}.
*/
public static SerializableMatcher> hasItem(
final SerializableMatcher matcher) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.hasItem(matcher);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#hasSize(int)}.
*/
public static SerializableMatcher> hasSize(final int size) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.hasSize(size);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#hasSize(Matcher)}.
*/
public static SerializableMatcher> hasSize(
final SerializableMatcher sizeMatcher) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.hasSize(sizeMatcher);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#iterableWithSize(int)}.
*/
public static SerializableMatcher> iterableWithSize(final int size) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.iterableWithSize(size);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to
* {@link Matchers#iterableWithSize(Matcher)}.
*/
public static SerializableMatcher> iterableWithSize(
final SerializableMatcher sizeMatcher) {
return fromSupplier(new SerializableSupplier>>() {
@Override
public Matcher> get() {
return Matchers.iterableWithSize(sizeMatcher);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#isIn(Collection)}.
*/
public static SerializableMatcher
isIn(final Collection collection) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.isIn(collection);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#isIn(Collection)}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}.
* They are explicitly not required or expected to be serializable via Java serialization.
*/
public static SerializableMatcher isIn(Coder coder, Collection collection) {
@SuppressWarnings("unchecked")
T[] items = (T[]) collection.toArray();
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.isIn(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#isIn(Object[])}.
*/
public static SerializableMatcher isIn(final T[] items) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.isIn(items);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#isIn(Object[])}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}.
* They are explicitly not required or expected to be serializable via Java serialization.
*/
public static SerializableMatcher isIn(Coder coder, T[] items) {
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.isIn(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#isOneOf}.
*/
@SafeVarargs
public static SerializableMatcher isOneOf(final T... elems) {
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.isOneOf(elems);
}
});
}
/**
* A {@link SerializableMatcher} with identical criteria to {@link Matchers#isOneOf}.
*
* The items of type {@code T} will be serialized using the provided {@link Coder}.
* They are explicitly not required or expected to be serializable via Java serialization.
*/
@SafeVarargs
public static SerializableMatcher isOneOf(Coder coder, T... items) {
final SerializableSupplier itemsSupplier =
new SerializableArrayViaCoder<>(coder, items);
return fromSupplier(new SerializableSupplier>() {
@Override
public Matcher get() {
return Matchers.isOneOf(itemsSupplier.get());
}
});
}
/**
* A {@link SerializableMatcher} that matches any {@link KV} with the specified key.
*/
public static SerializableMatcher>
kvWithKey(K key) {
return new KvKeyMatcher(equalTo(key));
}
/**
* A {@link SerializableMatcher} that matches any {@link KV} with the specified key.
*
* The key of type {@code K} will be serialized using the provided {@link Coder}.
* It is explicitly not required or expected to be serializable via Java serialization.
*/
public static SerializableMatcher>
kvWithKey(Coder coder, K key) {
return new KvKeyMatcher(equalTo(coder, key));
}
/**
* A {@link SerializableMatcher} that matches any {@link KV} with matching key.
*/
public static