Skip to content

Commit

Permalink
Implement SoftAssertions (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
VanRoy committed Dec 15, 2019
1 parent 88d64e9 commit 2101191
Show file tree
Hide file tree
Showing 16 changed files with 614 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/main/java/org/assertj/db/api/AbstractColumnAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public abstract class AbstractColumnAssert<D extends AbstractDbData<D>, A extend
/**
* Column on which do the assertion.
*/
private final Column column;
protected final Column column;

/**
* Constructor.
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/assertj/db/api/AbstractRowAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public abstract class AbstractRowAssert<D extends AbstractDbData<D>, A extends A
/**
* Row on which do the assertion.
*/
private final Row row;
protected final Row row;

/**
* Constructor.
Expand Down
65 changes: 65 additions & 0 deletions src/main/java/org/assertj/db/api/AbstractSoftAssertions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* 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.
*
* Copyright 2012-2016 the original author or authors.
*/
package org.assertj.db.api;

import org.assertj.core.internal.Failures;
import org.assertj.core.util.Lists;

import java.util.List;

/**
* Base class of AssertJ-DB SoftAssertions.
*
* @author Julien Roy
*/
public class AbstractSoftAssertions {

protected final SoftProxies proxies = new SoftProxies();

public <T, V> V proxy(Class<V> assertClass, Class<T> actualClass, T actual) {
return this.proxies.create(assertClass, actualClass, actual);
}

public void fail(String failureMessage) {
AssertionError error = Failures.instance().failure(failureMessage);
this.proxies.collectError(error);
}

public void fail(String failureMessage, Object... args) {
AssertionError error = Failures.instance().failure(String.format(failureMessage, args));
this.proxies.collectError(error);
}

public void fail(String failureMessage, Throwable realCause) {
AssertionError error = Failures.instance().failure(failureMessage);
error.initCause(realCause);
this.proxies.collectError(error);
}

public void failBecauseExceptionWasNotThrown(Class<? extends Throwable> throwableClass) {
this.shouldHaveThrown(throwableClass);
}

public void shouldHaveThrown(Class<? extends Throwable> throwableClass) {
AssertionError error = Failures.instance().expectedThrowableNotThrown(throwableClass);
this.proxies.collectError(error);
}

public List<Throwable> errorsCollected() {
return Lists.newArrayList(this.proxies.errorsCollected());
}

public boolean wasSuccess() {
return this.proxies.wasSuccess();
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/assertj/db/api/ChangeAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class ChangeAssert
/**
* The actual change on which the assertion is.
*/
private final Change change;
protected final Change change;

/**
* Position of navigation to row.
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/assertj/db/api/ChangeColumnAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ public class ChangeColumnAssert
/**
* The name of the column.
*/
private final String columnName;
protected final String columnName;
/**
* The actual value at start point.
*/
private final Value valueAtStartPoint;
protected final Value valueAtStartPoint;

/**
* The actual value at end point.
*/
private final Value valueAtEndPoint;
protected final Value valueAtEndPoint;

/**
* Position of navigation to row.
Expand Down
125 changes: 125 additions & 0 deletions src/main/java/org/assertj/db/api/ProxifyPositionResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* 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.
*
* Copyright 2012-2016 the original author or authors.
*/
package org.assertj.db.api;

import org.assertj.core.api.ObjectArrayAssert;
import org.assertj.core.internal.cglib.proxy.MethodInterceptor;
import org.assertj.core.internal.cglib.proxy.MethodProxy;
import org.assertj.core.util.Arrays;
import org.assertj.db.type.Change;
import org.assertj.db.type.Column;
import org.assertj.db.type.Row;
import org.assertj.db.type.Value;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import static org.assertj.db.util.Proxies.isProxified;
import static org.assertj.db.util.Proxies.unProxy;

/**
* Method interceptor that proxify result of assertions methods.
* Useful for navigation assertion methods like ( column(...) , row(...) ).
*
* @author Julien Roy
*/
class ProxifyPositionResult implements MethodInterceptor {
private final SoftProxies proxies;

ProxifyPositionResult(SoftProxies proxies) {
this.proxies = proxies;
}

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = proxy.invokeSuper(obj, args);
if (isProxified(result.getClass()) || actual(result) == null) {
return result;
}
return this.proxies.create(result.getClass(), actualClass(result), actual(result));
}

private static Class[] actualClass(Object result) {

if (result instanceof AbstractColumnAssert) {
return Arrays.array(
unProxy(((AbstractColumnAssert) result).origin.getClass()),
Column.class
);
} else if (result instanceof AbstractRowAssert) {
return Arrays.array(
unProxy(((AbstractRowAssert) result).origin.getClass()),
Row.class
);
} else if (result instanceof AbstractValueAssert) {
return Arrays.array(
unProxy(((AbstractValueAssert) result).origin.getClass()),
Value.class
);
} else if (result instanceof ChangeAssert) {
return Arrays.array(
unProxy(((ChangeAssert) result).origin.getClass()),
Change.class
);
} else if (result instanceof ChangeColumnAssert) {
return Arrays.array(
unProxy(((ChangeColumnAssert) result).origin.getClass()),
String.class,
Value.class,
Value.class
);
} else if (result instanceof ObjectArrayAssert) {
return Arrays.array(Array.newInstance(Object.class, 0).getClass());
} else {
Type actualType = ((ParameterizedType) result.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
Class type = actualType instanceof ParameterizedType ?
(Class) ((ParameterizedType) actualType).getRawType() :
(Class) actualType;
return Arrays.array(type);
}
}

private static Object[] actual(Object result) {
if (result instanceof AbstractColumnAssert) {
return Arrays.array(
((AbstractColumnAssert) result).origin,
((AbstractColumnAssert) result).column
);
} else if (result instanceof AbstractRowAssert) {
return Arrays.array(
((AbstractRowAssert) result).origin,
((AbstractRowAssert) result).row
);
} else if (result instanceof AbstractValueAssert) {
return Arrays.array(
((AbstractValueAssert) result).origin,
((AbstractValueAssert) result).value
);
} else if (result instanceof ChangeAssert) {
return Arrays.array(
((ChangeAssert) result).origin,
((ChangeAssert) result).change
);
} else if (result instanceof ChangeColumnAssert) {
return Arrays.array(
((ChangeColumnAssert) result).origin,
((ChangeColumnAssert) result).columnName,
((ChangeColumnAssert) result).valueAtStartPoint,
((ChangeColumnAssert) result).valueAtEndPoint
);
} else {
return null;
}
}
}
71 changes: 71 additions & 0 deletions src/main/java/org/assertj/db/api/SoftAssertions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* 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.
*
* Copyright 2012-2016 the original author or authors.
*/
package org.assertj.db.api;

import org.assertj.core.api.SoftAssertionError;
import org.assertj.core.groups.Properties;
import org.assertj.db.type.Changes;
import org.assertj.db.type.Request;
import org.assertj.db.type.Table;

import java.util.List;

/**
* Implementation of AssertJ SoftAssertions for {@link Table}, {@link Request} and {@link Changes}.
*
* This implementation works like AssertJ SoftAssertions implementation by providing you with
* proxies of the AssertJ-DB assertion objects.
*
* For more details see AssertJ implementation : {@link org.assertj.core.api.SoftAssertions}
*
* @author Julien Roy
*/
public final class SoftAssertions extends AbstractSoftAssertions {

/**
* Creates a new instance of {@link TableAssert}.
*
* @param table The table to assert on.
* @return The created assertion object.
*/
public TableAssert assertThat(Table table) {
return proxy(TableAssert.class, Table.class, table);
}

/**
* Creates a new instance of {@link RequestAssert}.
*
* @param request The request to assert on.
* @return The created assertion object.
*/
public RequestAssert assertThat(Request request) {
return proxy(RequestAssert.class, Request.class, request);
}

/**
* Creates a new instance of {@link ChangesAssert}.
*
* @param changes The changes to assert on.
* @return The created assertion object.
*/
public ChangesAssert assertThat(Changes changes) {
return proxy(ChangesAssert.class, Changes.class, changes);
}

public void assertAll() {
List<Throwable> errors = this.errorsCollected();
if (!errors.isEmpty()) {
throw new SoftAssertionError(Properties.extractProperty("message", String.class).from(errors));
}
}
}
81 changes: 81 additions & 0 deletions src/main/java/org/assertj/db/api/SoftProxies.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* 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.
*
* Copyright 2012-2016 the original author or authors.
*/
package org.assertj.db.api;

import org.assertj.core.api.ErrorCollector;
import org.assertj.core.internal.cglib.proxy.Callback;
import org.assertj.core.internal.cglib.proxy.CallbackFilter;
import org.assertj.core.internal.cglib.proxy.Enhancer;
import org.assertj.core.util.Arrays;

import java.lang.reflect.Method;
import java.util.List;

/**
* Proxy implementation utilities.
*
* @author Julien Roy
*/
class SoftProxies {
private final ErrorCollector collector = new ErrorCollector();

SoftProxies() {
}

void collectError(Throwable error) {
this.collector.addError(error);
}

List<Throwable> errorsCollected() {
return this.collector.errors();
}

@SuppressWarnings("unchecked")
<V, T> V create(Class<V> assertClass, Class<T> actualClass, T actual) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(assertClass);
enhancer.setCallbackFilter(SoftProxies.CollectErrorsOrCreateExtractedProxy.FILTER);
enhancer.setCallbacks(new Callback[] { this.collector, new ProxifyPositionResult(this) });
return (V) enhancer.create((Class[]) Arrays.array(new Class[] { actualClass }), Arrays.array(new Object[] { actual }));
}

@SuppressWarnings("unchecked")
<V> V create(Class<V> assertClass, Class[] paramClass, Object[] params) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(assertClass);
enhancer.setCallbackFilter(SoftProxies.CollectErrorsOrCreateExtractedProxy.FILTER);
enhancer.setCallbacks(new Callback[] { this.collector, new ProxifyPositionResult(this) });
return (V) enhancer.create(paramClass, params);
}

public boolean wasSuccess() {
return this.collector.wasSuccess();
}

private enum CollectErrorsOrCreateExtractedProxy implements CallbackFilter {
FILTER;

public int accept(Method method) {
return this.isPositionMethod(method) ? 1 : 0;
}

private boolean isPositionMethod(Method method) {
String methodName = method.getName();
return
java.util.Arrays.asList("change", "column", "row", "value").contains(methodName) ||
methodName.startsWith("changeOf") ||
methodName.startsWith("rowAt") ||
methodName.startsWith("of");
}
}
}
Loading

0 comments on commit 2101191

Please sign in to comment.