Skip to content

Commit 7836a79

Browse files
committed
Implement SoftAssertions (#58)
1 parent 88d64e9 commit 7836a79

16 files changed

+615
-30
lines changed

src/main/java/org/assertj/db/api/AbstractColumnAssert.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public abstract class AbstractColumnAssert<D extends AbstractDbData<D>, A extend
5555
/**
5656
* Column on which do the assertion.
5757
*/
58-
private final Column column;
58+
protected final Column column;
5959

6060
/**
6161
* Constructor.

src/main/java/org/assertj/db/api/AbstractRowAssert.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public abstract class AbstractRowAssert<D extends AbstractDbData<D>, A extends A
5959
/**
6060
* Row on which do the assertion.
6161
*/
62-
private final Row row;
62+
protected final Row row;
6363

6464
/**
6565
* Constructor.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2016 the original author or authors.
12+
*/
13+
package org.assertj.db.api;
14+
15+
import org.assertj.core.internal.Failures;
16+
import org.assertj.core.util.Lists;
17+
18+
import java.util.List;
19+
20+
/**
21+
* Base class of AssertJ-DB SoftAssertions.
22+
*
23+
* @author Julien Roy
24+
*/
25+
public class AbstractSoftAssertions {
26+
27+
protected final SoftProxies proxies = new SoftProxies();
28+
29+
public <T, V> V proxy(Class<V> assertClass, Class<T> actualClass, T actual) {
30+
return this.proxies.create(assertClass, actualClass, actual);
31+
}
32+
33+
public void fail(String failureMessage) {
34+
AssertionError error = Failures.instance().failure(failureMessage);
35+
this.proxies.collectError(error);
36+
}
37+
38+
public void fail(String failureMessage, Object... args) {
39+
AssertionError error = Failures.instance().failure(String.format(failureMessage, args));
40+
this.proxies.collectError(error);
41+
}
42+
43+
public void fail(String failureMessage, Throwable realCause) {
44+
AssertionError error = Failures.instance().failure(failureMessage);
45+
error.initCause(realCause);
46+
this.proxies.collectError(error);
47+
}
48+
49+
public void failBecauseExceptionWasNotThrown(Class<? extends Throwable> throwableClass) {
50+
this.shouldHaveThrown(throwableClass);
51+
}
52+
53+
public void shouldHaveThrown(Class<? extends Throwable> throwableClass) {
54+
AssertionError error = Failures.instance().expectedThrowableNotThrown(throwableClass);
55+
this.proxies.collectError(error);
56+
}
57+
58+
public List<Throwable> errorsCollected() {
59+
return Lists.newArrayList(this.proxies.errorsCollected());
60+
}
61+
62+
public boolean wasSuccess() {
63+
return this.proxies.wasSuccess();
64+
}
65+
}

src/main/java/org/assertj/db/api/ChangeAssert.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class ChangeAssert
4444
/**
4545
* The actual change on which the assertion is.
4646
*/
47-
private final Change change;
47+
protected final Change change;
4848

4949
/**
5050
* Position of navigation to row.

src/main/java/org/assertj/db/api/ChangeColumnAssert.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ public class ChangeColumnAssert
4343
/**
4444
* The name of the column.
4545
*/
46-
private final String columnName;
46+
protected final String columnName;
4747
/**
4848
* The actual value at start point.
4949
*/
50-
private final Value valueAtStartPoint;
50+
protected final Value valueAtStartPoint;
5151

5252
/**
5353
* The actual value at end point.
5454
*/
55-
private final Value valueAtEndPoint;
55+
protected final Value valueAtEndPoint;
5656

5757
/**
5858
* Position of navigation to row.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2016 the original author or authors.
12+
*/
13+
package org.assertj.db.api;
14+
15+
import org.assertj.core.api.ObjectArrayAssert;
16+
import org.assertj.core.internal.cglib.proxy.MethodInterceptor;
17+
import org.assertj.core.internal.cglib.proxy.MethodProxy;
18+
import org.assertj.core.util.Arrays;
19+
import org.assertj.db.type.Change;
20+
import org.assertj.db.type.Column;
21+
import org.assertj.db.type.Row;
22+
import org.assertj.db.type.Value;
23+
24+
import java.lang.reflect.Array;
25+
import java.lang.reflect.Method;
26+
import java.lang.reflect.ParameterizedType;
27+
import java.lang.reflect.Type;
28+
29+
import static org.assertj.db.util.Proxies.isProxified;
30+
import static org.assertj.db.util.Proxies.unProxy;
31+
32+
/**
33+
* Method interceptor that proxify result of assertions methods.
34+
* Useful for navigation assertion methods like ( column(...) , row(...) ).
35+
*
36+
* @author Julien Roy
37+
*/
38+
class ProxifyPositionResult implements MethodInterceptor {
39+
private final SoftProxies proxies;
40+
41+
ProxifyPositionResult(SoftProxies proxies) {
42+
this.proxies = proxies;
43+
}
44+
45+
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
46+
Object result = proxy.invokeSuper(obj, args);
47+
if (isProxified(result.getClass()) || actual(result) == null) {
48+
return result;
49+
}
50+
return this.proxies.create(result.getClass(), actualClass(result), actual(result));
51+
}
52+
53+
private static Class[] actualClass(Object result) {
54+
55+
if (result instanceof AbstractColumnAssert) {
56+
return Arrays.array(
57+
unProxy(((AbstractColumnAssert) result).origin.getClass()),
58+
Column.class
59+
);
60+
} else if (result instanceof AbstractRowAssert) {
61+
return Arrays.array(
62+
unProxy(((AbstractRowAssert) result).origin.getClass()),
63+
Row.class
64+
);
65+
} else if (result instanceof AbstractValueAssert) {
66+
return Arrays.array(
67+
unProxy(((AbstractValueAssert) result).origin.getClass()),
68+
Value.class
69+
);
70+
} else if (result instanceof ChangeAssert) {
71+
return Arrays.array(
72+
unProxy(((ChangeAssert) result).origin.getClass()),
73+
Change.class
74+
);
75+
} else if (result instanceof ChangeColumnAssert) {
76+
return Arrays.array(
77+
unProxy(((ChangeColumnAssert) result).origin.getClass()),
78+
String.class,
79+
Value.class,
80+
Value.class
81+
);
82+
} else if (result instanceof ObjectArrayAssert) {
83+
return Arrays.array(Array.newInstance(Object.class, 0).getClass());
84+
} else {
85+
Type actualType = ((ParameterizedType) result.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
86+
Class type = actualType instanceof ParameterizedType ?
87+
(Class) ((ParameterizedType) actualType).getRawType() :
88+
(Class) actualType;
89+
return Arrays.array(type);
90+
}
91+
}
92+
93+
private static Object[] actual(Object result) {
94+
if (result instanceof AbstractColumnAssert) {
95+
return Arrays.array(
96+
((AbstractColumnAssert) result).origin,
97+
((AbstractColumnAssert) result).column
98+
);
99+
} else if (result instanceof AbstractRowAssert) {
100+
return Arrays.array(
101+
((AbstractRowAssert) result).origin,
102+
((AbstractRowAssert) result).row
103+
);
104+
} else if (result instanceof AbstractValueAssert) {
105+
return Arrays.array(
106+
((AbstractValueAssert) result).origin,
107+
((AbstractValueAssert) result).value
108+
);
109+
} else if (result instanceof ChangeAssert) {
110+
return Arrays.array(
111+
((ChangeAssert) result).origin,
112+
((ChangeAssert) result).change
113+
);
114+
} else if (result instanceof ChangeColumnAssert) {
115+
return Arrays.array(
116+
((ChangeColumnAssert) result).origin,
117+
((ChangeColumnAssert) result).columnName,
118+
((ChangeColumnAssert) result).valueAtStartPoint,
119+
((ChangeColumnAssert) result).valueAtEndPoint
120+
);
121+
} else {
122+
return null;
123+
}
124+
}
125+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2016 the original author or authors.
12+
*/
13+
package org.assertj.db.api;
14+
15+
import org.assertj.core.api.SoftAssertionError;
16+
import org.assertj.core.groups.Properties;
17+
import org.assertj.db.type.Changes;
18+
import org.assertj.db.type.Request;
19+
import org.assertj.db.type.Table;
20+
21+
import java.util.List;
22+
23+
/**
24+
* Implementation of AssertJ SoftAssertions for {@link Table}, {@link Request} and {@link Changes}.
25+
*
26+
* This implementation works like AssertJ SoftAssertions implementation by providing you with
27+
* proxies of the AssertJ-DB assertion objects.
28+
*
29+
* For more details see AssertJ implementation : {@link org.assertj.core.api.SoftAssertions}
30+
*
31+
* @author Julien Roy
32+
*/
33+
public final class SoftAssertions extends AbstractSoftAssertions {
34+
35+
/**
36+
* Creates a new instance of {@link TableAssert}.
37+
*
38+
* @param table The table to assert on.
39+
* @return The created assertion object.
40+
*/
41+
public TableAssert assertThat(Table table) {
42+
return proxy(TableAssert.class, Table.class, table);
43+
}
44+
45+
/**
46+
* Creates a new instance of {@link RequestAssert}.
47+
*
48+
* @param request The request to assert on.
49+
* @return The created assertion object.
50+
*/
51+
public RequestAssert assertThat(Request request) {
52+
return proxy(RequestAssert.class, Request.class, request);
53+
}
54+
55+
/**
56+
* Creates a new instance of {@link ChangesAssert}.
57+
*
58+
* @param changes The changes to assert on.
59+
* @return The created assertion object.
60+
*/
61+
public ChangesAssert assertThat(Changes changes) {
62+
return proxy(ChangesAssert.class, Changes.class, changes);
63+
}
64+
65+
public void assertAll() {
66+
List<Throwable> errors = this.errorsCollected();
67+
if (!errors.isEmpty()) {
68+
throw new SoftAssertionError(Properties.extractProperty("message", String.class).from(errors));
69+
}
70+
}
71+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2016 the original author or authors.
12+
*/
13+
package org.assertj.db.api;
14+
15+
import org.assertj.core.api.ErrorCollector;
16+
import org.assertj.core.internal.cglib.proxy.Callback;
17+
import org.assertj.core.internal.cglib.proxy.CallbackFilter;
18+
import org.assertj.core.internal.cglib.proxy.Enhancer;
19+
import org.assertj.core.util.Arrays;
20+
21+
import java.lang.reflect.Method;
22+
import java.util.List;
23+
24+
/**
25+
* Proxy implementation utilities.
26+
*
27+
* @author Julien Roy
28+
*/
29+
class SoftProxies {
30+
private final ErrorCollector collector = new ErrorCollector();
31+
32+
SoftProxies() {
33+
}
34+
35+
void collectError(Throwable error) {
36+
this.collector.addError(error);
37+
}
38+
39+
List<Throwable> errorsCollected() {
40+
return this.collector.errors();
41+
}
42+
43+
@SuppressWarnings("unchecked")
44+
<V, T> V create(Class<V> assertClass, Class<T> actualClass, T actual) {
45+
Enhancer enhancer = new Enhancer();
46+
enhancer.setSuperclass(assertClass);
47+
enhancer.setCallbackFilter(SoftProxies.CollectErrorsOrCreateExtractedProxy.FILTER);
48+
enhancer.setCallbacks(new Callback[] { this.collector, new ProxifyPositionResult(this) });
49+
return (V) enhancer.create((Class[]) Arrays.array(new Class[] { actualClass }), Arrays.array(new Object[] { actual }));
50+
}
51+
52+
@SuppressWarnings("unchecked")
53+
<V> V create(Class<V> assertClass, Class[] paramClass, Object[] params) {
54+
Enhancer enhancer = new Enhancer();
55+
enhancer.setSuperclass(assertClass);
56+
enhancer.setCallbackFilter(SoftProxies.CollectErrorsOrCreateExtractedProxy.FILTER);
57+
enhancer.setCallbacks(new Callback[] { this.collector, new ProxifyPositionResult(this) });
58+
return (V) enhancer.create(paramClass, params);
59+
}
60+
61+
public boolean wasSuccess() {
62+
return this.collector.wasSuccess();
63+
}
64+
65+
private enum CollectErrorsOrCreateExtractedProxy implements CallbackFilter {
66+
FILTER;
67+
68+
public int accept(Method method) {
69+
return this.isPositionMethod(method) ? 1 : 0;
70+
}
71+
72+
private boolean isPositionMethod(Method method) {
73+
String methodName = method.getName();
74+
return
75+
java.util.Arrays.asList("change", "column", "row", "value").contains(methodName) ||
76+
methodName.startsWith("changeOf") ||
77+
methodName.startsWith("rowAt") ||
78+
methodName.startsWith("of");
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)