package book.example.async.notifications;
import book.example.async.Timeout;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import java.util.ArrayList;
import java.util.List;
public class NotificationTrace<T> {
private final Object traceLock = new Object();
private final List<T> trace = new ArrayList<T>();
private long timeoutMs = 1000L;
public long getTimeout() {
return timeoutMs;
}
public void setTimeout(long newTimeoutMs) {
this.timeoutMs = newTimeoutMs;
}
public void append(T message) {
synchronized (traceLock) {
trace.add(message);
traceLock.notifyAll();
}
}
public void containsNotification(Matcher<? super T> criteria)
throws InterruptedException {
Timeout timeout = new Timeout(timeoutMs);
synchronized (traceLock) {
NotificationStream<T> stream = new NotificationStream<T>(trace, criteria);
while (!stream.hasMatched()) {
if (timeout.hasTimedOut()) {
throw new AssertionError(failureDescriptionFrom(criteria));
}
timeout.waitOn(traceLock);
}
}
}
private String failureDescriptionFrom(Matcher<? super T> acceptanceCriteria) {
StringDescription description = new StringDescription();
description.appendText("no message matching ")
.appendDescriptionOf(acceptanceCriteria)
.appendText("received within " + timeoutMs + "ms\n");
if (trace.isEmpty()) {
description.appendText("received nothing");
} else {
description.appendValueList("received:\n ", "\n ", "", trace);
}
return description.toString();
}
public static class NotificationStream<N> {
private final List<N> notifications;
private final Matcher<? super N> criteria;
private int next = 0;
public NotificationStream(List<N> notifications, Matcher<? super N> criteria) {
this.notifications = notifications;
this.criteria = criteria;
}
public boolean hasMatched() {
while (next < notifications.size()) {
if (criteria.matches(notifications.get(next)))
return true;
next++;
}
return false;
}
}
}