diff --git a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java index e3fe3cb..8c40ccb 100644 --- a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java @@ -14,6 +14,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Sets.newHashSet; import static com.google.common.collect.Sets.newLinkedHashSet; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; @@ -76,6 +77,8 @@ public class ClassUtil { private static final Comparator GETTER_COMPARATOR = Comparator.comparing(Method::getName); public static final Package JAVA_LANG_PACKAGE = Object.class.getPackage(); private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private static final Set FORBIDDEN_ENUM_GETTER_NAMES = newHashSet("name", "values", "ordinal"); + private static final Set FORBIDDEN_GETTER_NAMES = newHashSet("hashCode", "toString"); /** * Call {@link #collectClasses(ClassLoader, String...)} with Thread.currentThread().getContextClassLoader() @@ -312,10 +315,48 @@ public static boolean inheritsCollectionOrIsIterable(Class returnType) { return Collection.class.isAssignableFrom(returnType) || Iterable.class.equals(returnType); } - public static boolean isStandardGetter(Method method) { - return isValidStandardGetterName(method.getName()) - && !Void.TYPE.equals(method.getReturnType()) - && method.getParameterTypes().length == 0; + public static boolean isGetter(Method method) { + return !Void.TYPE.equals(method.getReturnType()) + && method.getParameterTypes().length == 0 + && !isForbiddenGetter(method) + && !isReturnGeneric(method); + } + + private static boolean isForbiddenGetter(Method method) { + return FORBIDDEN_GETTER_NAMES.contains(method.getName()) + || isForbiddenEnumGetter(method); + } + + private static boolean isForbiddenEnumGetter(Method method) { + Class declaringClass = method.getDeclaringClass(); + boolean isEnum = declaringClass.isEnum() || declaringClass == java.lang.Enum.class; + return isEnum && FORBIDDEN_ENUM_GETTER_NAMES.contains(method.getName()); + } + + private static boolean isReturnGeneric(Method method) { + Type returnType = method.getGenericReturnType(); + return containsGenericType(returnType); + } + + private static boolean containsGenericType(Type type) { + return isGenericType(type) + || isParameterizedByGenericType(type); + } + + private static boolean isGenericType(Type type) { + return type instanceof java.lang.reflect.TypeVariable; + } + + private static boolean isParameterizedByGenericType(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) { + if (containsGenericType(actualTypeArgument)) { + return true; + } + } + } + return false; } public static boolean isPredicate(Method method) { @@ -389,11 +430,6 @@ public static boolean isValidGetterName(String methodName) { PREDICATE_PREFIXES = Collections.unmodifiableMap(map); } - private static boolean isValidStandardGetterName(String name) { - Matcher m = PREFIX_PATTERN.matcher(name); - return m.find() && m.group().equals(GET_PREFIX); - } - public static String getPredicatePrefix(String name) { Matcher m = PREFIX_PATTERN.matcher(name); return m.find() ? m.group() : null; @@ -438,7 +474,7 @@ && isGetter(method, includeAnnotations, isClassAnnotated)) { } private static boolean isGetter(Method method, Set> includeAnnotations, boolean isClassAnnotated) { - return isStandardGetter(method) + return isGetter(method) || isPredicate(method) || isAnnotated(method, includeAnnotations, isClassAnnotated); } @@ -772,10 +808,12 @@ private static String booleanPropertyOf(String memberName) { return memberName; } - private static String getterProperty(String memberName) { + public static String getterProperty(String memberName) { if (memberName.startsWith(GET_PREFIX)) { String propertyWithCapitalLetter = removeStart(memberName, GET_PREFIX); - return uncapitalize(propertyWithCapitalLetter); + if (!propertyWithCapitalLetter.isEmpty()) { + return uncapitalize(propertyWithCapitalLetter); + } } return memberName; } diff --git a/src/test/java/org/assertj/assertions/generator/data/nba/Player.java b/src/test/java/org/assertj/assertions/generator/data/nba/Player.java index 383aea9..a319d2d 100644 --- a/src/test/java/org/assertj/assertions/generator/data/nba/Player.java +++ b/src/test/java/org/assertj/assertions/generator/data/nba/Player.java @@ -60,7 +60,7 @@ public void setDisabled(boolean isDisabled) { this.isDisabled = isDisabled; } - public Name getName() { + public Name name() { return name; } diff --git a/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java b/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java index 811b3db..49e3c06 100644 --- a/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java +++ b/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java @@ -55,7 +55,7 @@ void should_create_valid_typename_from_class_for_user_defined_type_in_same_packa @Test void should_create_valid_typename_from_class_for_user_defined_type_in_different_package() throws Exception { - getterDescription = new GetterDescription("name", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("getName")); + getterDescription = new GetterDescription("name", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("name")); assertThat(getterDescription.getName()).isEqualTo("name"); assertThat(getterDescription.getTypeName()).isEqualTo("org.assertj.assertions.generator.data.Name"); assertThat(getterDescription.getFullyQualifiedTypeName()).isEqualTo("org.assertj.assertions.generator.data.Name"); diff --git a/src/test/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverterTest.java b/src/test/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverterTest.java index 49de052..2d6c3f1 100644 --- a/src/test/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverterTest.java +++ b/src/test/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverterTest.java @@ -55,7 +55,7 @@ void should_build_player_class_description() { assertThat(classDescription.getFullyQualifiedClassName()).isEqualTo("org.assertj.assertions.generator.data.nba.Player"); assertThat(classDescription.getFullyQualifiedOuterClassName()).isEqualTo("org.assertj.assertions.generator.data.nba.Player"); assertThat(classDescription.getFullyQualifiedClassNameWithoutGenerics()).isEqualTo(classDescription.getFullyQualifiedClassName()); - assertThat(classDescription.getGettersDescriptions()).hasSize(19); + assertThat(classDescription.getGettersDescriptions()).hasSize(21); assertThat(classDescription.getAssertClassName()).isEqualTo("PlayerAssert"); assertThat(classDescription.getAssertClassFilename()).isEqualTo("PlayerAssert.java"); assertThat(classDescription.getFullyQualifiedAssertClassName()).isEqualTo("org.assertj.assertions.generator.data.nba.PlayerAssert"); diff --git a/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java b/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java index 8460033..fa235d9 100644 --- a/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java +++ b/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java @@ -63,12 +63,13 @@ import static org.assertj.assertions.generator.util.ClassUtil.getPredicatePrefix; import static org.assertj.assertions.generator.util.ClassUtil.getSimpleNameWithOuterClass; import static org.assertj.assertions.generator.util.ClassUtil.getterMethodsOf; +import static org.assertj.assertions.generator.util.ClassUtil.getterProperty; import static org.assertj.assertions.generator.util.ClassUtil.inheritsCollectionOrIsIterable; import static org.assertj.assertions.generator.util.ClassUtil.isBoolean; import static org.assertj.assertions.generator.util.ClassUtil.isInnerPackageOf; import static org.assertj.assertions.generator.util.ClassUtil.isJavaLangType; import static org.assertj.assertions.generator.util.ClassUtil.isPredicate; -import static org.assertj.assertions.generator.util.ClassUtil.isStandardGetter; +import static org.assertj.assertions.generator.util.ClassUtil.isGetter; import static org.assertj.assertions.generator.util.ClassUtil.isValidGetterName; import static org.assertj.assertions.generator.util.ClassUtil.propertyNameOf; import static org.assertj.assertions.generator.util.ClassUtil.resolveTypeNameInPackage; @@ -179,14 +180,15 @@ void should_return_true_if_class_implements_iterable_interface() { @Test void should_return_true_if_method_is_a_standard_getter() throws Exception { - assertThat(isStandardGetter(Player.class.getMethod("getTeam", NO_PARAMS))).isTrue(); + assertThat(isGetter(Player.class.getMethod("getTeam", NO_PARAMS))).isTrue(); + assertThat(isGetter(Player.class.getMethod("isRookie", NO_PARAMS))).isTrue(); + assertThat(isGetter(Player.class.getMethod("name", NO_PARAMS))).isTrue(); } @Test void should_return_false_if_method_is_not_a_standard_getter() throws Exception { - assertThat(isStandardGetter(Player.class.getMethod("isRookie", NO_PARAMS))).isFalse(); - assertThat(isStandardGetter(Player.class.getMethod("getVoid", NO_PARAMS))).isFalse(); - assertThat(isStandardGetter(Player.class.getMethod("getWithParam", String.class))).isFalse(); + assertThat(isGetter(Player.class.getMethod("getVoid", NO_PARAMS))).isFalse(); + assertThat(isGetter(Player.class.getMethod("getWithParam", String.class))).isFalse(); } @Test @@ -264,6 +266,13 @@ void should_not_return_inherited_getters_methods() throws Exception { .doesNotContain(ArtWork.class.getMethod("getTitle", NO_PARAMS)); } + @Test + void should_return_property_name_from_getter_method_name() throws Exception { + assertThat(getterProperty("getName")).isEqualTo("name"); + assertThat(getterProperty("name")).isEqualTo("name"); + assertThat(getterProperty("get")).isEqualTo("get"); + } + @ParameterizedTest @FieldSource("NESTED_CLASSES") void should_return_inner_class_name_with_outer_class_name(NestedClass nestedClass) { diff --git a/src/test/resources/AbstractAnnotatedClassAssert.expected.txt b/src/test/resources/AbstractAnnotatedClassAssert.expected.txt index 75e931b..5288a7a 100644 --- a/src/test/resources/AbstractAnnotatedClassAssert.expected.txt +++ b/src/test/resources/AbstractAnnotatedClassAssert.expected.txt @@ -86,4 +86,27 @@ public abstract class AbstractAnnotatedClassAssert, return myself; } + /** + * Verifies that the actual Player's get is equal to the given one. + * @param get the given get to compare the actual Player's get to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's get is not equal to the given one. + */ + public S hasGet(String get) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting get of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualGet = actual.get(); + if (!Objects.deepEquals(actualGet, get)) { + failWithMessage(assertjErrorMessage, actual, get, actualGet); + } + + // return the current assertion for method chaining + return myself; + } + + /** + * Verifies that the actual Player's is is equal to the given one. + * @param is the given is to compare the actual Player's is to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's is is not equal to the given one. + */ + public S hasIs(String is) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting is of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualIs = actual.is(); + if (!Objects.deepEquals(actualIs, is)) { + failWithMessage(assertjErrorMessage, actual, is, actualIs); + } + + // return the current assertion for method chaining + return myself; + } + /** * Verifies that the actual Player's name is equal to the given one. * @param name the given name to compare the actual Player's name to. @@ -128,7 +174,7 @@ public abstract class AbstractPlayerAssert, String assertjErrorMessage = "\nExpecting name of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; // null safe check - org.assertj.assertions.generator.data.Name actualName = actual.getName(); + org.assertj.assertions.generator.data.Name actualName = actual.name(); if (!Objects.deepEquals(actualName, name)) { failWithMessage(assertjErrorMessage, actual, name, actualName); } diff --git a/src/test/resources/AbstractPlayerAssert.generated.in.custom.package.expected.txt b/src/test/resources/AbstractPlayerAssert.generated.in.custom.package.expected.txt index f82b84d..1f1417c 100644 --- a/src/test/resources/AbstractPlayerAssert.generated.in.custom.package.expected.txt +++ b/src/test/resources/AbstractPlayerAssert.generated.in.custom.package.expected.txt @@ -115,6 +115,52 @@ public abstract class AbstractPlayerAssert, return myself; } + /** + * Verifies that the actual Player's get is equal to the given one. + * @param get the given get to compare the actual Player's get to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's get is not equal to the given one. + */ + public S hasGet(String get) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting get of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualGet = actual.get(); + if (!Objects.deepEquals(actualGet, get)) { + failWithMessage(assertjErrorMessage, actual, get, actualGet); + } + + // return the current assertion for method chaining + return myself; + } + + /** + * Verifies that the actual Player's is is equal to the given one. + * @param is the given is to compare the actual Player's is to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's is is not equal to the given one. + */ + public S hasIs(String is) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting is of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualIs = actual.is(); + if (!Objects.deepEquals(actualIs, is)) { + failWithMessage(assertjErrorMessage, actual, is, actualIs); + } + + // return the current assertion for method chaining + return myself; + } + /** * Verifies that the actual Player's name is equal to the given one. * @param name the given name to compare the actual Player's name to. @@ -129,7 +175,7 @@ public abstract class AbstractPlayerAssert, String assertjErrorMessage = "\nExpecting name of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; // null safe check - org.assertj.assertions.generator.data.Name actualName = actual.getName(); + org.assertj.assertions.generator.data.Name actualName = actual.name(); if (!Objects.deepEquals(actualName, name)) { failWithMessage(assertjErrorMessage, actual, name, actualName); } diff --git a/src/test/resources/AnnotatedClassAssert.flat.expected.txt b/src/test/resources/AnnotatedClassAssert.flat.expected.txt index bf2603b..cf4be87 100644 --- a/src/test/resources/AnnotatedClassAssert.flat.expected.txt +++ b/src/test/resources/AnnotatedClassAssert.flat.expected.txt @@ -97,4 +97,27 @@ public class AnnotatedClassAssert extends AbstractObjectAssert { return this; } + /** + * Verifies that the actual Player's get is equal to the given one. + * @param get the given get to compare the actual Player's get to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's get is not equal to the given one. + */ + public PlayerAssert hasGet(String get) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting get of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualGet = actual.get(); + if (!Objects.deepEquals(actualGet, get)) { + failWithMessage(assertjErrorMessage, actual, get, actualGet); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player's is is equal to the given one. + * @param is the given is to compare the actual Player's is to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's is is not equal to the given one. + */ + public PlayerAssert hasIs(String is) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting is of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualIs = actual.is(); + if (!Objects.deepEquals(actualIs, is)) { + failWithMessage(assertjErrorMessage, actual, is, actualIs); + } + + // return the current assertion for method chaining + return this; + } + /** * Verifies that the actual Player's name is equal to the given one. * @param name the given name to compare the actual Player's name to. @@ -139,7 +185,7 @@ public class PlayerAssert extends AbstractObjectAssert { String assertjErrorMessage = "\nExpecting name of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; // null safe check - org.assertj.assertions.generator.data.Name actualName = actual.getName(); + org.assertj.assertions.generator.data.Name actualName = actual.name(); if (!Objects.deepEquals(actualName, name)) { failWithMessage(assertjErrorMessage, actual, name, actualName); } diff --git a/src/test/resources/PlayerAssert.generated.in.custom.package.flat.expected.txt b/src/test/resources/PlayerAssert.generated.in.custom.package.flat.expected.txt index 5efe8a5..b03252f 100644 --- a/src/test/resources/PlayerAssert.generated.in.custom.package.flat.expected.txt +++ b/src/test/resources/PlayerAssert.generated.in.custom.package.flat.expected.txt @@ -126,6 +126,52 @@ public class PlayerAssert extends AbstractObjectAssert { return this; } + /** + * Verifies that the actual Player's get is equal to the given one. + * @param get the given get to compare the actual Player's get to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's get is not equal to the given one. + */ + public PlayerAssert hasGet(String get) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting get of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualGet = actual.get(); + if (!Objects.deepEquals(actualGet, get)) { + failWithMessage(assertjErrorMessage, actual, get, actualGet); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player's is is equal to the given one. + * @param is the given is to compare the actual Player's is to. + * @return this assertion object. + * @throws AssertionError - if the actual Player's is is not equal to the given one. + */ + public PlayerAssert hasIs(String is) { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // overrides the default error message with a more explicit one + String assertjErrorMessage = "\nExpecting is of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; + + // null safe check + String actualIs = actual.is(); + if (!Objects.deepEquals(actualIs, is)) { + failWithMessage(assertjErrorMessage, actual, is, actualIs); + } + + // return the current assertion for method chaining + return this; + } + /** * Verifies that the actual Player's name is equal to the given one. * @param name the given name to compare the actual Player's name to. @@ -140,7 +186,7 @@ public class PlayerAssert extends AbstractObjectAssert { String assertjErrorMessage = "\nExpecting name of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; // null safe check - org.assertj.assertions.generator.data.Name actualName = actual.getName(); + org.assertj.assertions.generator.data.Name actualName = actual.name(); if (!Objects.deepEquals(actualName, name)) { failWithMessage(assertjErrorMessage, actual, name, actualName); }