Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#203 added EQUALS_FAST and HASH_CODE_FAST #205

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/pl/pojo/tester/api/assertion/Method.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import pl.pojo.tester.internal.tester.AbstractTester;
import pl.pojo.tester.internal.tester.ConstructorTester;
import pl.pojo.tester.internal.tester.EqualsFastTester;
import pl.pojo.tester.internal.tester.EqualsTester;
import pl.pojo.tester.internal.tester.GetterTester;
import pl.pojo.tester.internal.tester.HashCodeFastTester;
import pl.pojo.tester.internal.tester.HashCodeTester;
import pl.pojo.tester.internal.tester.SetterTester;
import pl.pojo.tester.internal.tester.ToStringTester;
Expand All @@ -18,7 +20,9 @@
*/
public enum Method {
EQUALS(new EqualsTester()),
EQUALS_FAST(new EqualsFastTester()),
HASH_CODE(new HashCodeTester()),
HASH_CODE_FAST(new HashCodeFastTester()),
SETTER(new SetterTester()),
GETTER(new GetterTester()),
TO_STRING(new ToStringTester()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import pl.pojo.tester.internal.utils.Sublists;

public class ObjectGenerator {

private static final Logger LOGGER = LoggerFactory.getLogger(ObjectGenerator.class);

private final AbstractFieldValueChanger abstractFieldValueChanger;
private final MultiValuedMap<Class<?>, ConstructorParameters> constructorParameters;
private final boolean thoroughTesting;

public ObjectGenerator(final AbstractFieldValueChanger abstractFieldValueChanger,
final MultiValuedMap<Class<?>, ConstructorParameters> constructorParameters) {
final MultiValuedMap<Class<?>, ConstructorParameters> constructorParameters,
final boolean thorough) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to pass some kind of policy, that would generate fields / list of fields e.g.

interface Permutator { public List<List<T>> permutate(final List<T> listToPermutate);}

class ThoroughFieldPermutator implements Permutator {}
class SublistFieldPermutator implements Permutator {}

this.abstractFieldValueChanger = abstractFieldValueChanger;
this.constructorParameters = constructorParameters;
this.thoroughTesting = thorough;
}

public Object createNewInstance(final Class<?> clazz) {
Expand Down Expand Up @@ -66,7 +70,7 @@ private List<Object> generateDifferentObjects(final int level,
final Map<Class<?>, List<Field>> userDefinedClassAndFieldToChangePairsMap = convertToClassAndFieldsToChange(
userDefinedClassAndFieldPredicatePairsMap);

final List<List<Field>> baseObjectFieldsPermutations = FieldUtils.permutations(baseClassFieldsToChange);
final List<List<Field>> baseObjectFieldsPermutations = fieldListsToUse(baseClassFieldsToChange);

final Object baseObject = createNewInstance(baseClass);
final LinkedList<Object> result = new LinkedList<>();
Expand Down Expand Up @@ -152,7 +156,7 @@ private List<Object> logAndPut(final int level, final Class<?> clazz, final List

private List<Object> generateDifferentObjects(final Class<?> clazz, final List<Field> fieldsToChange) {
final List<Object> differentObjects;
final List<List<Field>> permutationOfFields = FieldUtils.permutations(fieldsToChange);
final List<List<Field>> permutationOfFields = fieldListsToUse(fieldsToChange);
final Object fieldObject = createNewInstance(clazz);

differentObjects = permutationOfFields.stream()
Expand Down Expand Up @@ -245,4 +249,11 @@ private List<Field> getAllFields(final Object object) {
return allFields;
}

protected List<List<Field>> fieldListsToUse(final List<Field> fields) {
if (thoroughTesting) {
return FieldUtils.permutations(fields);
} else {
return Sublists.subsequences(fields);
}
}
}
17 changes: 13 additions & 4 deletions src/main/java/pl/pojo/tester/internal/tester/AbstractTester.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ public abstract class AbstractTester {
ObjectGenerator objectGenerator;
private MultiValuedMap<Class<?>, ConstructorParameters> constructorParameters = new ArrayListValuedHashMap<>();
private AbstractFieldValueChanger fieldValuesChanger = DefaultFieldValueChanger.INSTANCE;

private boolean thoroughTesting = true;

public AbstractTester() {
this(DefaultFieldValueChanger.INSTANCE);
}

public AbstractTester(final AbstractFieldValueChanger abstractFieldValueChanger) {
objectGenerator = new ObjectGenerator(abstractFieldValueChanger, constructorParameters);
objectGenerator = new ObjectGenerator(abstractFieldValueChanger, constructorParameters, thoroughTesting);
}

public void test(final Class<?> clazz) {
Expand Down Expand Up @@ -62,12 +62,21 @@ public void testAll(final ClassAndFieldPredicatePair... classesAndFieldPredicate

public void setFieldValuesChanger(final AbstractFieldValueChanger fieldValuesChanger) {
this.fieldValuesChanger = fieldValuesChanger;
objectGenerator = new ObjectGenerator(fieldValuesChanger, constructorParameters);
objectGenerator = new ObjectGenerator(fieldValuesChanger, constructorParameters, thoroughTesting);
}

public void setUserDefinedConstructors(final MultiValuedMap<Class<?>, ConstructorParameters> constructorParameters) {
this.constructorParameters = constructorParameters;
objectGenerator = new ObjectGenerator(fieldValuesChanger, constructorParameters);
objectGenerator = new ObjectGenerator(fieldValuesChanger, constructorParameters, thoroughTesting);
}

public boolean isThoroughTesting() {
return thoroughTesting;
}

public void setThoroughTesting(final boolean thoroughTesting) {
this.thoroughTesting = thoroughTesting;
objectGenerator = new ObjectGenerator(fieldValuesChanger, constructorParameters, thoroughTesting);
}

@Override
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/pl/pojo/tester/internal/tester/EqualsFastTester.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package pl.pojo.tester.internal.tester;

import pl.pojo.tester.internal.field.AbstractFieldValueChanger;

public class EqualsFastTester extends EqualsTester {

public EqualsFastTester() {
super();
setThoroughTesting(false);
}

public EqualsFastTester(final AbstractFieldValueChanger abstractFieldValueChanger) {
super(abstractFieldValueChanger);
setThoroughTesting(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package pl.pojo.tester.internal.tester;

import pl.pojo.tester.internal.field.AbstractFieldValueChanger;

/**
* Created by me on 26/08/17.
*/
public class HashCodeFastTester extends HashCodeTester {

public HashCodeFastTester() {
super();
setThoroughTesting(false);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://stackoverflow.com/a/3404369

You can create protected constructor in HashCodeTester with boolean parameter and then call super(true)
Same in EqualsFastTester

}

public HashCodeFastTester(final AbstractFieldValueChanger abstractFieldValueChanger) {
super(abstractFieldValueChanger);
setThoroughTesting(false);
}
}
29 changes: 29 additions & 0 deletions src/main/java/pl/pojo/tester/internal/utils/Sublists.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package pl.pojo.tester.internal.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public final class Sublists {
private Sublists() {
}

/**
* Given a list of objects, return a list of sublists, i-th sublist includes i-th element of
* the original list and all elements that follow it in the original list.
* All returned lists are read-only and backed by a copy of the original list, so later changes
* in the original list will not affect the returned sublists.
*
* @param list list of objects
* @param <T> the type of list element
* @return sublists of list
*/
public static <T> List<List<T>> subsequences(final List<T> list) {
final List<T> copyOfList = new ArrayList<>(list);
final List<List<T>> res = new ArrayList<>();
for (int i = 0; i < copyOfList.size(); i++) {
res.add(Collections.unmodifiableList(copyOfList.subList(i, copyOfList.size())));
}
return Collections.unmodifiableList(res);
}
}
139 changes: 139 additions & 0 deletions src/test/java/pl/pojo/tester/api/FastTestingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package pl.pojo.tester.api;

import classesForTest.packageFilter.A;
import classesForTest.packageFilter.B;
import classesForTest.packageFilter.C;
import classesForTest.packageFilter.next.D;
import classesForTest.packageFilter.next.E;
import org.junit.jupiter.api.Test;
import pl.pojo.tester.api.assertion.Method;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static pl.pojo.tester.api.assertion.Assertions.assertPojoMethodsFor;


public class FastTestingTest {

@Test
void ShouldCompleteInReasonableTime() {
long start = System.currentTimeMillis();
{
// given
final Class<?> classUnderTest = Medium.class;

// when

// then
assertPojoMethodsFor(classUnderTest)
.testing(Method.EQUALS_FAST, Method.HASH_CODE_FAST)
.areWellImplemented();
}
long end = System.currentTimeMillis();
assertThat(end - start).isLessThan(500l);
}
}

class Medium {
int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u;

@Override
public boolean equals(Object o1) {
if (this == o1) {
return true;
}
if (o1 == null || getClass() != o1.getClass()) {
return false;
}

Medium medium = (Medium) o1;

if (a != medium.a) {
return false;
}
if (b != medium.b) {
return false;
}
if (c != medium.c) {
return false;
}
if (d != medium.d) {
return false;
}
if (e != medium.e) {
return false;
}
if (f != medium.f) {
return false;
}
if (g != medium.g) {
return false;
}
if (h != medium.h) {
return false;
}
if (i != medium.i) {
return false;
}
if (j != medium.j) {
return false;
}
if (k != medium.k) {
return false;
}
if (l != medium.l) {
return false;
}
if (m != medium.m) {
return false;
}
if (n != medium.n) {
return false;
}
if (o != medium.o) {
return false;
}
if (p != medium.p) {
return false;
}
if (q != medium.q) {
return false;
}
if (r != medium.r) {
return false;
}
if (s != medium.s) {
return false;
}
if (t != medium.t) {
return false;
}
return u == medium.u;
}

@Override
public int hashCode() {
int result = a;
result = 31 * result + b;
result = 31 * result + c;
result = 31 * result + d;
result = 31 * result + e;
result = 31 * result + f;
result = 31 * result + g;
result = 31 * result + h;
result = 31 * result + i;
result = 31 * result + j;
result = 31 * result + k;
result = 31 * result + l;
result = 31 * result + m;
result = 31 * result + n;
result = 31 * result + o;
result = 31 * result + p;
result = 31 * result + q;
result = 31 * result + r;
result = 31 * result + s;
result = 31 * result + t;
result = 31 * result + u;
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import pl.pojo.tester.internal.assertion.AbstractAssertionError;
import pl.pojo.tester.internal.field.AbstractFieldValueChanger;
import pl.pojo.tester.internal.field.DefaultFieldValueChanger;
import pl.pojo.tester.internal.tester.EqualsFastTester;
import pl.pojo.tester.internal.tester.EqualsTester;
import pl.pojo.tester.internal.tester.HashCodeFastTester;
import pl.pojo.tester.internal.tester.HashCodeTester;
import pl.pojo.tester.internal.utils.CollectionUtils;

Expand Down Expand Up @@ -53,7 +55,21 @@ public void Should_Add_Equals_Tester() {
.containsExactly(expectedTester);
}

@Test
@Test
public void Should_Add_Equals_Fast_Tester() {
// given
final AbstractAssertion abstractAssertion = new AbstractAssertionImplementation();
final EqualsTester expectedTester = new EqualsFastTester();

// when
abstractAssertion.testing(Method.EQUALS_FAST);

// then
assertThat(abstractAssertion.testers).usingRecursiveFieldByFieldElementComparator()
.containsExactly(expectedTester);
}

@Test
public void Should_Add_Equals_And_Hash_Code_Testers() {
// given
final AbstractAssertion abstractAssertion = new AbstractAssertionImplementation();
Expand All @@ -68,7 +84,22 @@ public void Should_Add_Equals_And_Hash_Code_Testers() {
.containsExactly(expectedTester1, expectedTester2);
}

@Test
@Test
public void Should_Add_Equals_Fast_And_Hash_Code_Fast_Testers() {
// given
final AbstractAssertion abstractAssertion = new AbstractAssertionImplementation();
final EqualsTester expectedTester1 = new EqualsFastTester();
final HashCodeTester expectedTester2 = new HashCodeFastTester();

// when
abstractAssertion.testing(Method.EQUALS_FAST, Method.HASH_CODE_FAST);

// then
assertThat(abstractAssertion.testers).usingRecursiveFieldByFieldElementComparator()
.containsExactly(expectedTester1, expectedTester2);
}

@Test
public void Should_Not_Throw_Exception_When_Class_Has_All_Methods_Well_Implemented() {
// given
final Class<?> classUnderTest = GoodPojo_Equals_HashCode_ToString.class;
Expand Down