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

com.google.cloud.dataflow.sdk.testing.SerializableMatchers Maven / Gradle / Ivy

Go to download

Google Cloud Dataflow Java SDK provides a simple, Java-based interface for processing virtually any size data using Google cloud resources. This artifact includes entire Dataflow Java SDK.

There is a newer version: 2.5.0
Show newest version
/*
 * 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 SerializableMatcher> kvWithKey( final SerializableMatcher keyMatcher) { return new KvKeyMatcher(keyMatcher); } /** * A {@link SerializableMatcher} that matches any {@link KV} with the specified value. */ public static SerializableMatcher> kvWithValue(V value) { return new KvValueMatcher(equalTo(value)); } /** * A {@link SerializableMatcher} that matches any {@link KV} with the specified value. * *

The value of type {@code V} will be serialized using the provided {@link Coder}. * It is explicitly not required or expected to be serializable via Java serialization. */ public static SerializableMatcher> kvWithValue(Coder coder, V value) { return new KvValueMatcher(equalTo(coder, value)); } /** * A {@link SerializableMatcher} that matches any {@link KV} with matching value. */ public static SerializableMatcher> kvWithValue( final SerializableMatcher valueMatcher) { return new KvValueMatcher<>(valueMatcher); } /** * A {@link SerializableMatcher} that matches any {@link KV} with matching key and value. */ public static SerializableMatcher> kv( final SerializableMatcher keyMatcher, final SerializableMatcher valueMatcher) { return SerializableMatchers.>allOf( SerializableMatchers.kvWithKey(keyMatcher), SerializableMatchers.kvWithValue(valueMatcher)); } /** * A {@link SerializableMatcher} with identical criteria to {@link Matchers#lessThan()}. */ public static & Serializable> SerializableMatcher lessThan( final T target) { return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.lessThan(target); } }); } /** * A {@link SerializableMatcher} with identical criteria to {@link Matchers#lessThan()}. * *

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 > SerializableMatcher lessThan(Coder coder, T target) { final SerializableSupplier targetSupplier = new SerializableViaCoder<>(coder, target); return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.lessThan(targetSupplier.get()); } }); } /** * A {@link SerializableMatcher} with identical criteria to * {@link Matchers#lessThanOrEqualTo()}. */ public static & Serializable> SerializableMatcher lessThanOrEqualTo( final T target) { return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.lessThanOrEqualTo(target); } }); } /** * A {@link SerializableMatcher} with identical criteria to * {@link Matchers#lessThanOrEqualTo()}. * *

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 > SerializableMatcher lessThanOrEqualTo( Coder coder, T target) { final SerializableSupplier targetSupplier = new SerializableViaCoder<>(coder, target); return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.lessThanOrEqualTo(targetSupplier.get()); } }); } /** * A {@link SerializableMatcher} with identical criteria to * {@link Matchers#not}. */ public static SerializableMatcher not(final SerializableMatcher matcher) { return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.not(matcher); } }); } /** * A {@link SerializableMatcher} with identical criteria to * {@link Matchers#nullValue}. */ public static SerializableMatcher nullValue() { return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.nullValue(); } }); } /** * A {@link SerializableMatcher} with identical criteria to {@link Matchers#startsWith}. */ public static SerializableMatcher startsWith(final String substring) { return fromSupplier(new SerializableSupplier>() { @Override public Matcher get() { return Matchers.startsWith(substring); } }); } private static class KvKeyMatcher extends BaseMatcher> implements SerializableMatcher> { private final SerializableMatcher keyMatcher; public KvKeyMatcher(SerializableMatcher keyMatcher) { this.keyMatcher = keyMatcher; } @Override public boolean matches(Object item) { @SuppressWarnings("unchecked") KV kvItem = (KV) item; return keyMatcher.matches(kvItem.getKey()); } @Override public void describeMismatch(Object item, Description mismatchDescription) { @SuppressWarnings("unchecked") KV kvItem = (KV) item; if (!keyMatcher.matches(kvItem.getKey())) { mismatchDescription.appendText("key did not match: "); keyMatcher.describeMismatch(kvItem.getKey(), mismatchDescription); } } @Override public void describeTo(Description description) { description.appendText("KV with key matching "); keyMatcher.describeTo(description); } @Override public String toString() { return MoreObjects.toStringHelper(this) .addValue(keyMatcher) .toString(); } } private static class KvValueMatcher extends BaseMatcher> implements SerializableMatcher> { private final SerializableMatcher valueMatcher; public KvValueMatcher(SerializableMatcher valueMatcher) { this.valueMatcher = valueMatcher; } @Override public boolean matches(Object item) { @SuppressWarnings("unchecked") KV kvItem = (KV) item; return valueMatcher.matches(kvItem.getValue()); } @Override public void describeMismatch(Object item, Description mismatchDescription) { @SuppressWarnings("unchecked") KV kvItem = (KV) item; if (!valueMatcher.matches(kvItem.getValue())) { mismatchDescription.appendText("value did not match: "); valueMatcher.describeMismatch(kvItem.getValue(), mismatchDescription); } } @Override public void describeTo(Description description) { description.appendText("KV with value matching "); valueMatcher.describeTo(description); } @Override public String toString() { return MoreObjects.toStringHelper(this) .addValue(valueMatcher) .toString(); } } /** * Constructs a {@link SerializableMatcher} from a non-serializable {@link Matcher} via * indirection through {@link SerializableSupplier}. * *

To wrap a {@link Matcher} which is not serializable, provide a {@link SerializableSupplier} * with a {@link SerializableSupplier#get()} method that returns a fresh instance of the * {@link Matcher} desired. The resulting {@link SerializableMatcher} will behave according to * the {@link Matcher} returned by {@link SerializableSupplier#get() get()} when it is invoked * during matching (which may occur on another machine, such as a Dataflow worker). * *

{@code
   * return fromSupplier(new SerializableSupplier>() {
   *     public Matcher get() {
   *       return new MyMatcherForT();
   *     }
   * });
   * }
*/ public static SerializableMatcher fromSupplier( SerializableSupplier> supplier) { return new SerializableMatcherFromSupplier<>(supplier); } /** * Supplies values of type {@code T}, and is serializable. Thus, even if {@code T} is not * serializable, the supplier can be serialized and provide a {@code T} wherever it is * deserialized. * * @param the type of value supplied. */ public interface SerializableSupplier extends Serializable { T get(); } /** * Since the delegate {@link Matcher} is not generally serializable, instead this takes a nullary * SerializableFunction to return such a matcher. */ private static class SerializableMatcherFromSupplier extends BaseMatcher implements SerializableMatcher { private SerializableSupplier> supplier; public SerializableMatcherFromSupplier(SerializableSupplier> supplier) { this.supplier = supplier; } @Override public void describeTo(Description description) { supplier.get().describeTo(description); } @Override public boolean matches(Object item) { return supplier.get().matches(item); } @Override public void describeMismatch(Object item, Description mismatchDescription) { supplier.get().describeMismatch(item, mismatchDescription); } } /** * Wraps any value that can be encoded via a {@link Coder} to make it {@link Serializable}. * This is not likely to be a good encoding, so should be used only for tests, where data * volume is small and minor costs are not critical. */ private static class SerializableViaCoder implements SerializableSupplier { /** Cached value that is not serialized. */ @Nullable private transient T value; /** The bytes of {@link #value} when encoded via {@link #coder}. */ private byte[] encodedValue; private Coder coder; public SerializableViaCoder(Coder coder, T value) { this.coder = coder; this.value = value; try { this.encodedValue = CoderUtils.encodeToByteArray(coder, value); } catch (CoderException exc) { throw new RuntimeException("Error serializing via Coder", exc); } } @Override public T get() { if (value == null) { try { value = CoderUtils.decodeFromByteArray(coder, encodedValue); } catch (CoderException exc) { throw new RuntimeException("Error deserializing via Coder", exc); } } return value; } } /** * Wraps any array with values that can be encoded via a {@link Coder} to make it * {@link Serializable}. This is not likely to be a good encoding, so should be used only for * tests, where data volume is small and minor costs are not critical. */ private static class SerializableArrayViaCoder implements SerializableSupplier { /** Cached value that is not serialized. */ @Nullable private transient T[] value; /** The bytes of {@link #value} when encoded via {@link #coder}. */ private byte[] encodedValue; private Coder> coder; public SerializableArrayViaCoder(Coder elementCoder, T[] value) { this.coder = ListCoder.of(elementCoder); this.value = value; try { this.encodedValue = CoderUtils.encodeToByteArray(coder, Arrays.asList(value)); } catch (CoderException exc) { throw UserCodeException.wrap(exc); } } @Override public T[] get() { if (value == null) { try { @SuppressWarnings("unchecked") T[] decoded = (T[]) CoderUtils.decodeFromByteArray(coder, encodedValue).toArray(); value = decoded; } catch (CoderException exc) { throw new RuntimeException("Error deserializing via Coder", exc); } } return value; } } }