Skip to content

Commit

Permalink
Allow different field and getter method naming standards
Browse files Browse the repository at this point in the history
  • Loading branch information
jqno committed Jun 29, 2023
1 parent a47999e commit 8c4476c
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.function.Function;
import nl.jqno.equalsverifier.Func.Func1;
import nl.jqno.equalsverifier.Func.Func2;
import nl.jqno.equalsverifier.api.EqualsVerifierApi;
Expand All @@ -20,21 +21,24 @@ public final class ConfiguredEqualsVerifier implements EqualsVerifierApi<Void> {
private final EnumSet<Warning> warningsToSuppress;
private final FactoryCache factoryCache;
private boolean usingGetClass;
private Function<String, String> fieldnameToGetter;

/** Constructor. */
public ConfiguredEqualsVerifier() {
this(EnumSet.noneOf(Warning.class), new FactoryCache(), false);
this(EnumSet.noneOf(Warning.class), new FactoryCache(), false, null);
}

/** Private constructor. For internal use only. */
private ConfiguredEqualsVerifier(
EnumSet<Warning> warningsToSuppress,
FactoryCache factoryCache,
boolean usingGetClass
boolean usingGetClass,
Function<String, String> fieldnameToGetter
) {
this.warningsToSuppress = warningsToSuppress;
this.factoryCache = factoryCache;
this.usingGetClass = usingGetClass;
this.fieldnameToGetter = fieldnameToGetter;
}

/**
Expand All @@ -46,7 +50,8 @@ public ConfiguredEqualsVerifier copy() {
return new ConfiguredEqualsVerifier(
EnumSet.copyOf(warningsToSuppress),
new FactoryCache().merge(factoryCache),
usingGetClass
usingGetClass,
fieldnameToGetter
);
}

Expand Down Expand Up @@ -91,6 +96,14 @@ public ConfiguredEqualsVerifier usingGetClass() {
return this;
}

@Override
public ConfiguredEqualsVerifier withFieldnameToGetterConverter(
Function<String, String> converter
) {
this.fieldnameToGetter = converter;
return this;

Check warning on line 104 in equalsverifier-core/src/main/java/nl/jqno/equalsverifier/ConfiguredEqualsVerifier.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 104 without causing a test to fail

replaced return value with null for withFieldnameToGetterConverter (0 tests run NullReturnValsMutator)
}

/** {@inheritDoc} */
@Override
public ConfiguredEqualsVerifier withResetCaches() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nl.jqno.equalsverifier.api;

import java.util.function.Function;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Func.Func1;
import nl.jqno.equalsverifier.Func.Func2;
Expand Down Expand Up @@ -70,6 +71,19 @@ public interface EqualsVerifierApi<T> {
*/
EqualsVerifierApi<T> usingGetClass();

/**
* Determines how a getter name can be derived from a field name.
*
* The default behavior is to uppercase the field's first letter and prepend 'get'. For
* instance, a field name 'employee' would correspond to getter name 'getEmployee'.
*
* This method can be used if your project has a different naming convention.
*
* @param converter A function that converts from field name to getter name.
* @return {@code this}, for easy method chaining.
*/
EqualsVerifierApi<T> withFieldnameToGetterConverter(Function<String, String> converter);

/**
* Signals that all internal caches need to be reset. This is useful when the test framework
* uses multiple ClassLoaders to run tests, causing {@link java.lang.Class} instances
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import nl.jqno.equalsverifier.ConfiguredEqualsVerifier;
Expand Down Expand Up @@ -70,6 +71,15 @@ public MultipleTypeEqualsVerifierApi usingGetClass() {
return this;
}

/** {@inheritDoc} */
@Override
public MultipleTypeEqualsVerifierApi withFieldnameToGetterConverter(
Function<String, String> converter
) {
ev.withFieldnameToGetterConverter(converter);
return this;

Check warning on line 80 in equalsverifier-core/src/main/java/nl/jqno/equalsverifier/api/MultipleTypeEqualsVerifierApi.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 80 without causing a test to fail

replaced return value with null for withFieldnameToGetterConverter (0 tests run NullReturnValsMutator)
}

/** {@inheritDoc} */
@Override
public MultipleTypeEqualsVerifierApi withResetCaches() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
package nl.jqno.equalsverifier.api;

import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.EqualsVerifierReport;
import nl.jqno.equalsverifier.Func.Func1;
import nl.jqno.equalsverifier.Func.Func2;
import nl.jqno.equalsverifier.Warning;
import nl.jqno.equalsverifier.internal.checkers.*;
import nl.jqno.equalsverifier.internal.checkers.AbstractDelegationChecker;
import nl.jqno.equalsverifier.internal.checkers.CachedHashCodeChecker;
import nl.jqno.equalsverifier.internal.checkers.Checker;
import nl.jqno.equalsverifier.internal.checkers.ExamplesChecker;
import nl.jqno.equalsverifier.internal.checkers.FieldsChecker;
import nl.jqno.equalsverifier.internal.checkers.HierarchyChecker;
import nl.jqno.equalsverifier.internal.checkers.MapEntryHashCodeRequirementChecker;
import nl.jqno.equalsverifier.internal.checkers.NullChecker;
import nl.jqno.equalsverifier.internal.checkers.RecordChecker;
import nl.jqno.equalsverifier.internal.checkers.SignatureChecker;
import nl.jqno.equalsverifier.internal.exceptions.MessagingException;
import nl.jqno.equalsverifier.internal.prefabvalues.FactoryCache;
import nl.jqno.equalsverifier.internal.util.*;
import nl.jqno.equalsverifier.internal.util.CachedHashCodeInitializer;
import nl.jqno.equalsverifier.internal.util.Configuration;
import nl.jqno.equalsverifier.internal.util.ErrorMessage;
import nl.jqno.equalsverifier.internal.util.FieldNameExtractor;
import nl.jqno.equalsverifier.internal.util.Formatter;
import nl.jqno.equalsverifier.internal.util.ObjenesisWrapper;
import nl.jqno.equalsverifier.internal.util.PrefabValuesApi;
import nl.jqno.equalsverifier.internal.util.Validations;

/**
* Helps to construct an {@link EqualsVerifier} test with a fluent API.
Expand All @@ -29,6 +51,7 @@ public class SingleTypeEqualsVerifierApi<T> implements EqualsVerifierApi<T> {
private FactoryCache factoryCache = new FactoryCache();
private CachedHashCodeInitializer<T> cachedHashCodeInitializer =
CachedHashCodeInitializer.passthrough();
private Function<String, String> fieldnameToGetter = null;
private Set<String> allExcludedFields = new HashSet<>();
private Set<String> allIncludedFields = new HashSet<>();
private Set<String> nonnullFields = new HashSet<>();
Expand Down Expand Up @@ -129,6 +152,15 @@ public SingleTypeEqualsVerifierApi<T> usingGetClass() {
return this;
}

/** {@inheritDoc} */
@Override
public SingleTypeEqualsVerifierApi<T> withFieldnameToGetterConverter(
Function<String, String> converter
) {
this.fieldnameToGetter = converter;
return this;
}

/**
* Signals that all given fields are not relevant for the {@code equals} contract. {@code
* EqualsVerifier} will not fail if one of these fields does not affect the outcome of {@code
Expand Down Expand Up @@ -396,6 +428,7 @@ private Configuration<T> buildConfig() {
redefinedSubclass,
usingGetClass,
warningsToSuppress,
fieldnameToGetter,
factoryCache,
ignoredAnnotationClassNames,
actualFields,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static nl.jqno.equalsverifier.internal.util.Assert.assertTrue;

import java.util.Set;
import java.util.function.Function;
import nl.jqno.equalsverifier.internal.exceptions.EqualsVerifierInternalBugException;
import nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues;
import nl.jqno.equalsverifier.internal.prefabvalues.TypeTag;
Expand All @@ -24,13 +25,15 @@ public class JpaLazyGetterFieldCheck<T> implements FieldCheck<T> {
private final Set<String> ignoredFields;
private final PrefabValues prefabValues;
private final AnnotationCache annotationCache;
private final Function<String, String> fieldnameToGetter;

public JpaLazyGetterFieldCheck(Configuration<T> config) {
this.type = config.getType();
this.accessor = config.getClassAccessor();
this.ignoredFields = config.getIgnoredFields();
this.prefabValues = config.getPrefabValues();
this.annotationCache = config.getAnnotationCache();
this.fieldnameToGetter = config.getFieldnameToGetter();
}

@Override
Expand All @@ -40,8 +43,7 @@ public void execute(
FieldAccessor fieldAccessor
) {
String fieldName = fieldAccessor.getFieldName();
String getterName =
"get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
String getterName = fieldnameToGetter.apply(fieldName);

if (ignoredFields.contains(fieldName) || !fieldIsLazy(fieldAccessor)) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package nl.jqno.equalsverifier.internal.util;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import nl.jqno.equalsverifier.Warning;
import nl.jqno.equalsverifier.internal.prefabvalues.FactoryCache;
Expand All @@ -17,13 +22,17 @@

public final class Configuration<T> {

private static final Function<String, String> DEFAULT_FIELDNAME_TO_GETTER_CONVERTER = fn ->
"get" + Character.toUpperCase(fn.charAt(0)) + fn.substring(1);

private final Class<T> type;
private final Set<String> nonnullFields;
private final CachedHashCodeInitializer<T> cachedHashCodeInitializer;
private final boolean hasRedefinedSuperclass;
private final Class<? extends T> redefinedSubclass;
private final boolean usingGetClass;
private final EnumSet<Warning> warningsToSuppress;
private final Function<String, String> fieldnameToGetter;

private final TypeTag typeTag;
private final PrefabValues prefabValues;
Expand All @@ -48,6 +57,7 @@ private Configuration(
Class<? extends T> redefinedSubclass,
boolean usingGetClass,
EnumSet<Warning> warningsToSuppress,
Function<String, String> fieldnameToGetter,
List<T> equalExamples,
List<T> unequalExamples
) {
Expand All @@ -63,6 +73,7 @@ private Configuration(
this.redefinedSubclass = redefinedSubclass;
this.usingGetClass = usingGetClass;
this.warningsToSuppress = warningsToSuppress;
this.fieldnameToGetter = fieldnameToGetter;
this.equalExamples = equalExamples;
this.unequalExamples = unequalExamples;
}
Expand All @@ -77,6 +88,7 @@ public static <T> Configuration<T> build(
Class<? extends T> redefinedSubclass,
boolean usingGetClass,
EnumSet<Warning> warningsToSuppress,
Function<String, String> fieldnameToGetter,
FactoryCache factoryCache,
Set<String> ignoredAnnotationClassNames,
Set<String> actualFields,
Expand All @@ -96,6 +108,9 @@ public static <T> Configuration<T> build(
includedFields,
actualFields
);
Function<String, String> converter = fieldnameToGetter != null
? fieldnameToGetter
: DEFAULT_FIELDNAME_TO_GETTER_CONVERTER;
List<T> unequals = ensureUnequalExamples(typeTag, classAccessor, unequalExamples);

return new Configuration<>(
Expand All @@ -111,6 +126,7 @@ public static <T> Configuration<T> build(
redefinedSubclass,
usingGetClass,
warningsToSuppress,
converter,
equalExamples,
unequals
);
Expand Down Expand Up @@ -233,6 +249,10 @@ public EnumSet<Warning> getWarningsToSuppress() {
return EnumSet.copyOf(warningsToSuppress);
}

public Function<String, String> getFieldnameToGetter() {
return fieldnameToGetter;
}

public List<T> getEqualExamples() {
return Collections.unmodifiableList(equalExamples);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public void lazyGettersPickedUpInSuper() {
EqualsVerifier.forClass(ChildOfLazyGetterContainer.class).usingGetClass().verify();
}

@Test
public void differentCodingStyle() {
EqualsVerifier
.forClass(DifferentCodingStyleContainer.class)
.suppress(Warning.NONFINAL_FIELDS)
.withFieldnameToGetterConverter(fn ->
"get" + Character.toUpperCase(fn.charAt(2)) + fn.substring(3)
)
.verify();
}

private void getterNotUsed(Class<?> type, String method) {
ExpectedException
.when(() -> EqualsVerifier.forClass(type).suppress(Warning.NONFINAL_FIELDS).verify())
Expand Down Expand Up @@ -470,4 +481,42 @@ public boolean equals(Object obj) {
return super.equals(obj);
}
}

@Entity
static class DifferentCodingStyleContainer {

// CHECKSTYLE OFF: MemberName
@OneToMany(fetch = FetchType.LAZY)
private String m_oneToMany;

@ManyToOne(fetch = FetchType.LAZY)
private String m_manyToOne;

// CHECKSTYLE ON: MemberName

public String getOneToMany() {
return m_oneToMany;
}

public String getManyToOne() {
return m_manyToOne;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof DifferentCodingStyleContainer)) {
return false;
}
DifferentCodingStyleContainer other = (DifferentCodingStyleContainer) obj;
return (
Objects.equals(getOneToMany(), other.getOneToMany()) &&
Objects.equals(getManyToOne(), other.getManyToOne())
);
}

@Override
public int hashCode() {
return Objects.hash(getOneToMany(), getManyToOne());
}
}
}

0 comments on commit 8c4476c

Please sign in to comment.