Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.bedrin.jdbc.sniffer.Spy Maven / Gradle / Ivy
package com.github.bedrin.jdbc.sniffer;
import com.github.bedrin.jdbc.sniffer.sql.StatementMetaData;
import java.io.Closeable;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import static com.github.bedrin.jdbc.sniffer.Sniffer.DEFAULT_THREAD_MATCHER;
import static com.github.bedrin.jdbc.sniffer.Query.ANY;
import static com.github.bedrin.jdbc.sniffer.util.ExceptionUtil.addSuppressed;
import static com.github.bedrin.jdbc.sniffer.util.ExceptionUtil.throwException;
/**
* Spy holds a number of queries which were executed at some point of time and uses it as a base for further assertions
* @see Sniffer#spy()
* @see Sniffer#expect(int)
* @since 2.0
*/
public class Spy> implements Closeable {
private Counter initialCount;
private Counter initialThreadLocalCount;
private volatile Collection executedStatements = new ConcurrentLinkedQueue();
private final WeakReference selfReference;
private final Thread owner;
private boolean closed = false;
private StackTraceElement[] closeStackTrace;
void addExecutedStatement(StatementMetaData statementMetaData) {
executedStatements.add(statementMetaData);
}
void resetExecutedStatements() {
executedStatements = new ConcurrentLinkedQueue();
}
public List getExecutedStatements(Threads threadMatcher) {
List statements;
switch (threadMatcher) {
case CURRENT:
statements = new ArrayList();
for (StatementMetaData statement : executedStatements) {
if (statement.owner == this.owner) {
statements.add(statement);
}
}
break;
case OTHERS:
statements = new ArrayList();
for (StatementMetaData statement : executedStatements) {
if (statement.owner == this.owner) {
statements.add(statement);
}
}
break;
case ANY:
default:
statements = new ArrayList(executedStatements);
}
return Collections.unmodifiableList(statements);
}
Spy() {
owner = Thread.currentThread();
selfReference = Sniffer.registerSpy(this);
reset();
}
private void initNumberOfQueries() {
this.initialCount = new Counter(Sniffer.COUNTER);
this.initialThreadLocalCount = new Counter(Sniffer.THREAD_LOCAL_COUNTER.get());
}
private List expectations = new ArrayList();
/**
* Wrapper for {@link Sniffer#spy()} method; useful for chaining
* @return a new {@link Spy} instance
* @since 2.0
*/
public Spy reset() {
checkOpened();
initNumberOfQueries();
resetExecutedStatements();
expectations.clear();
return self();
}
/**
* @return number of SQL statements executed by current thread since some fixed moment of time
* @since 2.0
*/
public int executedStatements() {
return executedStatements(DEFAULT_THREAD_MATCHER);
}
/**
* @param threadMatcher chooses {@link Thread}s for calculating the number of executed queries
* @return number of SQL statements executed since some fixed moment of time
* @since 2.0
*/
public int executedStatements(Threads threadMatcher) {
return executedStatements(threadMatcher, Query.ANY);
}
/**
* @param threadMatcher chooses {@link Thread}s for calculating the number of executed queries
* @return number of SQL statements executed since some fixed moment of time
* @since 2.2
*/
public int executedStatements(Threads threadMatcher, Query query) {
checkOpened();
switch (threadMatcher) {
case ANY:
return Sniffer.COUNTER.executedStatements(query) - initialCount.executedStatements(query);
case CURRENT:
return Sniffer.THREAD_LOCAL_COUNTER.get().executedStatements(query) - initialThreadLocalCount.executedStatements(query);
case OTHERS:
return Sniffer.COUNTER.executedStatements(query) - Sniffer.THREAD_LOCAL_COUNTER.get().executedStatements(query)
- initialCount.executedStatements(query) + initialThreadLocalCount.executedStatements(query);
default:
throw new IllegalArgumentException(String.format("Unknown thread matcher %s", threadMatcher.getClass().getName()));
}
}
// never methods
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 0, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C expectNever() {
checkOpened();
return expectNever(DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 0, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C expectNever(Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 0, threadMatcher, ANY));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 0, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C expectNever(Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 0, DEFAULT_THREAD_MATCHER, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 0, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectNever(Threads threadMatcher, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 0, threadMatcher, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 0, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectNever(Query query, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 0, threadMatcher, query));
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 0, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C verifyNever() throws WrongNumberOfQueriesError {
checkOpened();
return verifyNever(DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 0, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C verifyNever(Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 0, threadMatcher, ANY).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 0, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C verifyNever(Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 0, DEFAULT_THREAD_MATCHER, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 0, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyNever(Threads threadMatcher, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 0, threadMatcher, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 0, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyNever(Query query, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 0, threadMatcher, query).validate();
return self();
}
// atMostOnce methods
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 1, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C expectAtMostOnce() {
checkOpened();
return expectAtMostOnce(DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 1, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C expectAtMostOnce(Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 1, threadMatcher, ANY));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 1, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C expectAtMostOnce(Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 1, DEFAULT_THREAD_MATCHER, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 1, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectAtMostOnce(Threads threadMatcher, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 1, threadMatcher, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, 1, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectAtMostOnce(Query query, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, 1, threadMatcher, query));
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 1, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C verifyAtMostOnce() throws WrongNumberOfQueriesError {
checkOpened();
return verifyAtMostOnce(DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 1, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C verifyAtMostOnce(Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 1, threadMatcher, ANY).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 1, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C verifyAtMostOnce(Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 1, DEFAULT_THREAD_MATCHER, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 1, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyAtMostOnce(Threads threadMatcher, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 1, threadMatcher, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, 1, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyAtMostOnce(Query query, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, 1, threadMatcher, query).validate();
return self();
}
// atMost methods
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C expectAtMost(int allowedStatements) {
checkOpened();
return expectAtMost(allowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C expectAtMost(int allowedStatements, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, allowedStatements, threadMatcher, ANY));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C expectAtMost(int allowedStatements, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, allowedStatements, DEFAULT_THREAD_MATCHER, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectAtMost(int allowedStatements, Threads threadMatcher, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, allowedStatements, threadMatcher, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectAtMost(int allowedStatements, Query query, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(0, allowedStatements, threadMatcher, query));
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C verifyAtMost(int allowedStatements) throws WrongNumberOfQueriesError {
checkOpened();
return verifyAtMost(allowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C verifyAtMost(int allowedStatements, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, allowedStatements, threadMatcher, ANY).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C verifyAtMost(int allowedStatements, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, allowedStatements, DEFAULT_THREAD_MATCHER, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyAtMost(int allowedStatements, Threads threadMatcher, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, allowedStatements, threadMatcher, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments 0, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyAtMost(int allowedStatements, Query query, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(0, allowedStatements, threadMatcher, query).validate();
return self();
}
// exact methods
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C expect(int allowedStatements) {
checkOpened();
return expect(allowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C expect(int allowedStatements, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, allowedStatements, threadMatcher, ANY));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C expect(int allowedStatements, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, allowedStatements, DEFAULT_THREAD_MATCHER, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expect(int allowedStatements, Threads threadMatcher, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, allowedStatements, threadMatcher, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expect(int allowedStatements, Query query, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, allowedStatements, threadMatcher, query));
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C verify(int allowedStatements) throws WrongNumberOfQueriesError {
checkOpened();
return verify(allowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C verify(int allowedStatements, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, allowedStatements, threadMatcher, ANY).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C verify(int allowedStatements, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, allowedStatements, DEFAULT_THREAD_MATCHER, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verify(int allowedStatements, Threads threadMatcher, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, allowedStatements, threadMatcher, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@code allowedStatements}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verify(int allowedStatements, Query query, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, allowedStatements, threadMatcher, query).validate();
return self();
}
// atLeast methods
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C expectAtLeast(int allowedStatements) {
checkOpened();
return expectAtLeast(allowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C expectAtLeast(int allowedStatements, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, threadMatcher, ANY));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C expectAtLeast(int allowedStatements, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, DEFAULT_THREAD_MATCHER, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectAtLeast(int allowedStatements, Threads threadMatcher, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, threadMatcher, query));
return self();
}
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C expectAtLeast(int allowedStatements, Query query, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, threadMatcher, query));
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C verifyAtLeast(int allowedStatements) throws WrongNumberOfQueriesError {
checkOpened();
return verifyAtLeast(allowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@code threads}, {@link Query#ANY}
* @since 2.0
*/
public C verifyAtLeast(int allowedStatements, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, threadMatcher, ANY).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@link Threads#CURRENT}, {@code queryType}
* @since 2.2
*/
public C verifyAtLeast(int allowedStatements, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, DEFAULT_THREAD_MATCHER, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyAtLeast(int allowedStatements, Threads threadMatcher, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, threadMatcher, query).validate();
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads, Query)} with arguments {@code allowedStatements}, {@link Integer#MAX_VALUE}, {@code threads}, {@code queryType}
* @since 2.2
*/
public C verifyAtLeast(int allowedStatements, Query query, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(allowedStatements, Integer.MAX_VALUE, threadMatcher, query).validate();
return self();
}
// between methods
/**
* Alias for {@link #expectBetween(int, int, Threads, Query)} with arguments {@code minAllowedStatements}, {@code maxAllowedStatements}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C expectBetween(int minAllowedStatements, int maxAllowedStatements) {
checkOpened();
return expectBetween(minAllowedStatements, maxAllowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Adds an expectation to the current instance that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @since 2.0
*/
public C expectBetween(int minAllowedStatements, int maxAllowedStatements, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, threadMatcher, ANY));
return self();
}
/**
* Adds an expectation to the current instance that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @since 2.2
*/
public C expectBetween(int minAllowedStatements, int maxAllowedStatements, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, DEFAULT_THREAD_MATCHER, query));
return self();
}
/**
* Adds an expectation to the current instance that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @since 2.2
*/
public C expectBetween(int minAllowedStatements, int maxAllowedStatements, Threads threadMatcher, Query query) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, threadMatcher, query));
return self();
}
/**
* Adds an expectation to the current instance that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @since 2.2
*/
public C expectBetween(int minAllowedStatements, int maxAllowedStatements, Query query, Threads threadMatcher) {
checkOpened();
expectations.add(new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, threadMatcher, query));
return self();
}
/**
* Alias for {@link #verifyBetween(int, int, Threads)} with arguments {@code minAllowedStatements}, {@link Threads#CURRENT}, {@link Query#ANY}
* @since 2.0
*/
public C verifyBetween(int minAllowedStatements, int maxAllowedStatements) throws WrongNumberOfQueriesError {
checkOpened();
return verifyBetween(minAllowedStatements, maxAllowedStatements, DEFAULT_THREAD_MATCHER);
}
/**
* Verifies that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.0
*/
public C verifyBetween(int minAllowedStatements, int maxAllowedStatements, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, threadMatcher, ANY).validate();
return self();
}
/**
* Verifies that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.2
*/
public C verifyBetween(int minAllowedStatements, int maxAllowedStatements, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, DEFAULT_THREAD_MATCHER, query).validate();
return self();
}
/**
* Verifies that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.2
*/
public C verifyBetween(int minAllowedStatements, int maxAllowedStatements, Threads threadMatcher, Query query) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, threadMatcher, query).validate();
return self();
}
/**
* Verifies that at least {@code minAllowedStatements} and at most
* {@code maxAllowedStatements} were called between the creation of the current instance
* and a call to {@link #verify()} method
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.2
*/
public C verifyBetween(int minAllowedStatements, int maxAllowedStatements, Query query, Threads threadMatcher) throws WrongNumberOfQueriesError {
checkOpened();
new ThreadMatcherExpectation(minAllowedStatements, maxAllowedStatements, threadMatcher, query).validate();
return self();
}
// end
/**
* Verifies all expectations added previously using {@code expect} methods family
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.0
*/
public void verify() throws WrongNumberOfQueriesError {
checkOpened();
WrongNumberOfQueriesError assertionError = getWrongNumberOfQueriesError();
if (null != assertionError) {
throw assertionError;
}
}
/**
*
* @return WrongNumberOfQueriesError or null if there are no errors
* @since 2.1
*/
public WrongNumberOfQueriesError getWrongNumberOfQueriesError() {
checkOpened();
WrongNumberOfQueriesError assertionError = null;
Throwable currentException = null;
for (Expectation expectation : expectations) {
try {
expectation.validate();
} catch (WrongNumberOfQueriesError e) {
if (null == assertionError) {
currentException = assertionError = e;
} else {
currentException.initCause(e);
currentException = e;
}
}
}
return assertionError;
}
/**
* Alias for {@link #verify()} method; it is useful for try-with-resource API:
*
*
* {@literal @}Test
* public void testTryWithResourceApi() throws SQLException {
* final Connection connection = DriverManager.getConnection("sniffer:jdbc:h2:mem:", "sa", "sa");
* try (@SuppressWarnings("unused") Spy s = Sniffer.expectAtMostOnce();
* Statement statement = connection.createStatement()) {
* statement.execute("SELECT 1 FROM DUAL");
* }
* }
* }
*
*
* @since 2.0
*/
public void close() {
try {
verify();
} finally {
Sniffer.removeSpyReference(selfReference);
closed = true;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
closeStackTrace = new StackTraceElement[stackTrace.length - 1];
System.arraycopy(stackTrace, 1, closeStackTrace, 0, stackTrace.length - 1);
}
}
private void checkOpened() {
if (closed) {
throw new SpyClosedException("Spy is closed", closeStackTrace);
}
}
/**
* Executes the {@link Sniffer.Executable#execute()} method on provided argument and verifies the expectations
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.0
*/
public C execute(Sniffer.Executable executable) {
checkOpened();
try {
executable.execute();
} catch (Throwable e) {
throw verifyAndAddToException(e);
}
verify();
return self();
}
/**
* Executes the {@link Runnable#run()} method on provided argument and verifies the expectations
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.0
*/
public C run(Runnable runnable) {
checkOpened();
try {
runnable.run();
} catch (Throwable e) {
throw verifyAndAddToException(e);
}
verify();
return self();
}
/**
* Executes the {@link Callable#call()} method on provided argument and verifies the expectations
* @throws WrongNumberOfQueriesError if wrong number of queries was executed
* @since 2.0
*/
public SpyWithValue call(Callable callable) {
checkOpened();
V result;
try {
result = callable.call();
} catch (Throwable e) {
throw verifyAndAddToException(e);
}
verify();
return new SpyWithValue(result);
}
private RuntimeException verifyAndAddToException(Throwable e) {
try {
verify();
} catch (WrongNumberOfQueriesError ae) {
if (!addSuppressed(e, ae)) {
ae.printStackTrace();
}
}
throwException(e);
return new RuntimeException(e);
}
private interface Expectation {
void validate() throws WrongNumberOfQueriesError;
}
private class ThreadMatcherExpectation implements Expectation {
private final int minimumQueries;
private final int maximumQueries;
private final Threads threadMatcher;
private final Query query;
public ThreadMatcherExpectation(int minimumQueries, int maximumQueries, Threads threadMatcher, Query query) {
this.minimumQueries = minimumQueries;
this.maximumQueries = maximumQueries;
this.threadMatcher = threadMatcher;
this.query = query;
}
public void validate() throws WrongNumberOfQueriesError {
int numQueries = executedStatements(threadMatcher, query);
if (numQueries > maximumQueries || numQueries < minimumQueries) {
throw new WrongNumberOfQueriesError(
threadMatcher,
minimumQueries, maximumQueries, numQueries,
getExecutedStatements(threadMatcher)
);
}
}
}
@SuppressWarnings("unchecked")
private C self() {
return (C) this;
}
}