From 3766e5bd731ee5c70fb97f1623104024d7f4ab0f Mon Sep 17 00:00:00 2001 From: Kevin Brightwell Date: Thu, 25 May 2017 09:04:37 -0400 Subject: [PATCH 1/5] Added type-safety and introspection capabilities This completes the "feature-parity" version of the work with deeper type inspection in the generation step. All "string-based" type safety has been replaced with reflection-based approaches that utilize better type safety. The follow things were done: * Utilized Guava's `TypeToken<>` to fully introspect the classes being loaded and utilize this information to do better generation * Added consistent ordering to properties based on the property name then the original member * Cleaned up some unneeded code after the switch * Added consistent "empty line" spacing -- there is no spaces on empty lines after generation * Added more predicate prefixes * Replaced usages of `line.separator` with `\n` because it causes issues on windows vs. unix * Updated tests to match any changes made This stage will be reviewed and then refactored (red-green-refactor!). Of particular note: * `Type` and `ClassUtil` should be one class * Check for more spacing issues, particularly extra new-lines * Any remarks from @joel-costigliola This works towards issues: #57, #51, and #92. --- pom.xml | 5 +- .../generator/AssertionGenerator.java | 9 +- .../AssertionsEntryPointGenerator.java | 7 +- .../generator/BaseAssertionGenerator.java | 158 +++--- .../cli/AssertionGeneratorLauncher.java | 54 +- .../description/ClassDescription.java | 54 +- .../description/DataDescription.java | 151 ++++-- .../description/FieldDescription.java | 39 +- .../description/GetterDescription.java | 42 +- .../description/TypeDescription.java | 129 ----- .../generator/description/TypeName.java | 235 --------- .../converter/ClassDescriptionConverter.java | 2 +- .../ClassToClassDescriptionConverter.java | 150 ++---- .../assertions/generator/util/ClassUtil.java | 173 +++---- .../assertions/generator/util/TypeUtil.java | 240 +++++++++ src/main/resources/logback.xml | 2 +- ..._hierarchical_assertion_class_template.txt | 1 - .../templates/has_assertion_template.txt | 2 +- .../has_assertion_template_for_char.txt | 4 +- .../has_assertion_template_for_character.txt | 2 +- .../has_assertion_template_for_primitive.txt | 2 +- ...sertion_template_for_primitive_wrapper.txt | 2 +- ...has_assertion_template_for_real_number.txt | 6 +- ...rtion_template_for_real_number_wrapper.txt | 4 +- ...as_assertion_template_for_whole_number.txt | 2 +- ...tion_template_for_whole_number_wrapper.txt | 2 +- ..._elements_assertion_template_for_array.txt | 13 +- ...ements_assertion_template_for_iterable.txt | 19 +- .../templates/is_assertion_template.txt | 8 +- .../is_wrapper_assertion_template.txt | 4 +- .../generator/AssertionGeneratorTest.java | 57 +- .../AssertionsEntryPointGeneratorTest.java | 35 +- .../generator/BeanWithExceptionsTest.java | 61 ++- .../assertions/generator/data/Keywords.java | 1 + .../assertions/generator/data/nba/Player.java | 45 +- .../description/FieldDescriptionTest.java | 75 ++- .../description/GetterDescriptionTest.java | 98 ++-- .../description/TypeDescriptionTest.java | 35 -- .../generator/description/TypeNameTest.java | 283 ---------- .../ClassToClassDescriptionConverterTest.java | 490 ++++++++++-------- .../generator/util/ClassUtilTest.java | 101 ++-- .../generator/util/TypeUtilTest.java | 100 ++++ .../AbstractArtWorkAssert.expected.txt | 4 +- .../AbstractMovieAssert.expected.txt | 20 +- .../AnnotatedClassAssert.expected.txt | 6 +- src/test/resources/ArtWorkAssert.expected.txt | 1 - ...AutoValueAnnotatedClassAssert.expected.txt | 6 +- .../BeanWithOneException.expected.txt | 112 ++-- .../resources/BooleanPredicates.expected.txt | 154 +++--- src/test/resources/CarAssert.expected.txt | 2 +- ...gDifferentClassesWithSameName.expected.txt | 4 +- .../resources/FieldPropertyClash.expected.txt | 2 +- src/test/resources/Keywords.expected.txt | 250 ++++----- src/test/resources/MovieAssert.expected.txt | 1 - .../resources/MovieAssert.flat.expected.txt | 24 +- ...sAssert.hierarchical.template.expected.txt | 1 - .../NestedClassAssert.template.expected.txt | 2 +- .../resources/PlayerAgentAssert.expected.txt | 2 +- src/test/resources/PlayerAssert.expected.txt | 376 +++++++++++--- .../resources/PrimitivesAssert.expected.txt | 258 ++++----- src/test/resources/TeamAssert.expected.txt | 74 +-- ...as_assertion_template_for_whole_number.txt | 2 +- 62 files changed, 2094 insertions(+), 2109 deletions(-) delete mode 100644 src/main/java/org/assertj/assertions/generator/description/TypeDescription.java delete mode 100644 src/main/java/org/assertj/assertions/generator/description/TypeName.java create mode 100644 src/main/java/org/assertj/assertions/generator/util/TypeUtil.java delete mode 100644 src/test/java/org/assertj/assertions/generator/description/TypeDescriptionTest.java delete mode 100644 src/test/java/org/assertj/assertions/generator/description/TypeNameTest.java create mode 100644 src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java diff --git a/pom.xml b/pom.xml index e65c1c6a..3d275874 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ org.apache.commons commons-lang3 - 3.1 + 3.5 commons-cli @@ -32,7 +32,8 @@ com.google.guava guava - 18.0 + + 20.0 ch.qos.logback diff --git a/src/main/java/org/assertj/assertions/generator/AssertionGenerator.java b/src/main/java/org/assertj/assertions/generator/AssertionGenerator.java index 75edeff9..bf142127 100644 --- a/src/main/java/org/assertj/assertions/generator/AssertionGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/AssertionGenerator.java @@ -12,12 +12,13 @@ */ package org.assertj.assertions.generator; +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.description.ClassDescription; + import java.io.File; import java.io.IOException; import java.util.Set; -import org.assertj.assertions.generator.description.ClassDescription; - public interface AssertionGenerator { @@ -127,7 +128,7 @@ public interface AssertionGenerator { * containing the file for the concrete final assertion. * @throws IOException if something went wrong when creating the assertion files. */ - File[] generateHierarchicalCustomAssertionFor(ClassDescription classDescription, Set> allClasses) throws IOException; + File[] generateHierarchicalCustomAssertionFor(ClassDescription classDescription, Set> allClasses) throws IOException; /** * Builds and returns the custom assertion java file content for the given {@link ClassDescription}. @@ -240,7 +241,7 @@ public interface AssertionGenerator { * @throws RuntimeException * if something went wrong when creating the assertion content. */ - String[] generateHierarchicalCustomAssertionContentFor(ClassDescription classDescription, Set> allClasses); + String[] generateHierarchicalCustomAssertionContentFor(ClassDescription classDescription, Set> allClasses); /** * Registers a template in the internal TemplateRegistry so that customers can override default templates. diff --git a/src/main/java/org/assertj/assertions/generator/AssertionsEntryPointGenerator.java b/src/main/java/org/assertj/assertions/generator/AssertionsEntryPointGenerator.java index 619c1fd9..555001e3 100644 --- a/src/main/java/org/assertj/assertions/generator/AssertionsEntryPointGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/AssertionsEntryPointGenerator.java @@ -12,13 +12,12 @@ */ package org.assertj.assertions.generator; +import org.assertj.assertions.generator.description.ClassDescription; + import java.io.File; import java.io.IOException; import java.util.Set; -import org.assertj.assertions.generator.AssertionsEntryPointType; -import org.assertj.assertions.generator.description.ClassDescription; - public interface AssertionsEntryPointGenerator { /** @@ -34,7 +33,7 @@ public interface AssertionsEntryPointGenerator { * a.b.c. * * @param classDescriptionSet the set of ClassDescription we want to generate an entry point for. - * @param assertionsEntryPointType the type of entry point class to generate + * @param assertionsEntryPointType the valueType of entry point class to generate * @param entryPointClassPackage the package of the generated entry point class * @return the assertions entry point class content */ diff --git a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java index 39879ebf..aed34e94 100644 --- a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,32 +12,28 @@ */ package org.assertj.assertions.generator; +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.Template.Type; import org.assertj.assertions.generator.description.ClassDescription; import org.assertj.assertions.generator.description.DataDescription; import org.assertj.assertions.generator.description.FieldDescription; import org.assertj.assertions.generator.description.GetterDescription; -import org.assertj.assertions.generator.description.TypeName; +import org.assertj.assertions.generator.util.TypeUtil; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; +import java.lang.reflect.Method; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkState; import static java.lang.String.format; -import static org.apache.commons.lang3.StringUtils.capitalize; -import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.apache.commons.lang3.StringUtils.remove; -import static org.apache.commons.lang3.StringUtils.replace; +import static org.apache.commons.lang3.StringUtils.*; import static org.assertj.assertions.generator.Template.Type.ASSERT_CLASS; +@SuppressWarnings("WeakerAccess") public class BaseAssertionGenerator implements AssertionGenerator, AssertionsEntryPointGenerator { static final String ABSTRACT_ASSERT_CLASS_PREFIX = "Abstract"; @@ -72,7 +68,7 @@ public class BaseAssertionGenerator implements AssertionGenerator, AssertionsEnt private static final String IMPORTS = "${imports}"; private static final String THROWS = "${throws}"; private static final String THROWS_JAVADOC = "${throws_javadoc}"; - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + private static final String LINE_SEPARATOR = "\n"; // assertions classes are generated in their package directory starting from targetBaseDirectory. // ex : com.nba.Player -> targetBaseDirectory/com/nba/PlayerAssert.java private String targetBaseDirectory = "."; @@ -134,7 +130,7 @@ public File generateCustomAssertionFor(ClassDescription classDescription) throws } @Override - public File[] generateHierarchicalCustomAssertionFor(ClassDescription classDescription, Set> allClasses) + public File[] generateHierarchicalCustomAssertionFor(ClassDescription classDescription, Set> allClasses) throws IOException { // Assertion content @@ -153,49 +149,47 @@ public File[] generateHierarchicalCustomAssertionFor(ClassDescription classDescr @Override public String[] generateHierarchicalCustomAssertionContentFor(ClassDescription classDescription, - Set> allClasses) { + Set> allClasses) { // use abstract class template first String abstractClassTemplateContent = templateRegistry.getTemplate(Type.ABSTRACT_ASSERT_CLASS).getContent(); StringBuilder abstractAssertClassContentBuilder = new StringBuilder(abstractClassTemplateContent); // generate assertion method for each property with a public getter - abstractAssertClassContentBuilder.append(generateAssertionsForDeclaredGettersOf(classDescription)); - abstractAssertClassContentBuilder.append(generateAssertionsForDeclaredPublicFieldsOf(classDescription)); + generateAssertionsForDeclaredGettersOf(abstractAssertClassContentBuilder, classDescription); + generateAssertionsForDeclaredPublicFieldsOf(abstractAssertClassContentBuilder, classDescription); // close class with } abstractAssertClassContentBuilder.append(LINE_SEPARATOR).append("}").append(LINE_SEPARATOR); // use concrete class template for the subclass of the generated abstract assert String concreteAssertClassContent = templateRegistry.getTemplate(Type.HIERARCHICAL_ASSERT_CLASS).getContent(); - StringBuilder concreteAssertClassContentBuilder = new StringBuilder(concreteAssertClassContent); // return a String array with the actual generated of the assertion class hierarchy String[] assertionClassesContent = new String[2]; assertionClassesContent[0] = fillAssertClassTemplate(abstractAssertClassContentBuilder.toString(), classDescription, allClasses, false); - assertionClassesContent[1] = fillAssertClassTemplate(concreteAssertClassContentBuilder.toString(), + assertionClassesContent[1] = fillAssertClassTemplate(concreteAssertClassContent, classDescription, null, true); return assertionClassesContent; } private String fillAssertClassTemplate(String template, ClassDescription classDescription, - Set> classesHierarchy, boolean concrete) { + Set> classesHierarchy, boolean concrete) { // Add any AssertJ needed imports only, other types are used with their fully qualified names to avoid a compilation // error when two types have the same - TreeSet assertjImports = new TreeSet(); - if (template.contains("Assertions.")) assertjImports.add(new TypeName("org.assertj.core.api.Assertions")); - if (template.contains("Objects.")) assertjImports.add(new TypeName("org.assertj.core.util.Objects")); - if (template.contains("Iterables.")) assertjImports.add(new TypeName("org.assertj.core.internal.Iterables")); + TreeSet assertjImports = new TreeSet<>(); + if (template.contains("Assertions.")) assertjImports.add("org.assertj.core.api.Assertions"); + if (template.contains("Objects.")) assertjImports.add("org.assertj.core.util.Objects"); + if (template.contains("Iterables.")) assertjImports.add("org.assertj.core.internal.Iterables"); - final TypeName superAssertionClass; + final String superAssertionClassName; // Add assertion supertype to imports if needed if (classesHierarchy == null || !classesHierarchy.contains(classDescription.getSuperType())) { - superAssertionClass = new TypeName("org.assertj.core.api.AbstractObjectAssert"); + superAssertionClassName = "org.assertj.core.api.AbstractObjectAssert"; } else { - final TypeName superTypeName = new TypeName(classDescription.getSuperType()); - superAssertionClass = new TypeName(abstractAssertClassNameOf(superTypeName), superTypeName.getPackageName()); + superAssertionClassName = abstractAssertClassNameOf(classDescription.getSuperType()); } - assertjImports.add(superAssertionClass); + assertjImports.add(superAssertionClassName); final String customAssertionClass = concrete ? assertClassNameOf(classDescription) : abstractAssertClassNameOf(classDescription); @@ -207,7 +201,7 @@ private String fillAssertClassTemplate(String template, ClassDescription classDe // className could be a nested class like "OuterClass.NestedClass", in that case assert class will be // OuterClassNestedClass template = replace(template, SUPER_ASSERTION_CLASS, - superAssertionClass.getSimpleNameWithOuterClassNotSeparatedByDots()); + TypeUtil.getTypeNameWithoutDots(superAssertionClassName)); template = replace(template, CLASS_TO_ASSERT, classDescription.getClassNameWithOuterClass()); template = replace(template, SELF_TYPE, selfType); template = replace(template, MYSELF, myself); @@ -228,8 +222,8 @@ public String generateCustomAssertionContentFor(ClassDescription classDescriptio StringBuilder assertionFileContentBuilder = new StringBuilder(classTemplateContent); // generate assertion method for each property with a public getter - assertionFileContentBuilder.append(generateAssertionsForGettersOf(classDescription)); - assertionFileContentBuilder.append(generateAssertionsForPublicFieldsOf(classDescription)); + generateAssertionsForGettersOf(assertionFileContentBuilder, classDescription); + generateAssertionsForPublicFieldsOf(assertionFileContentBuilder, classDescription); // close class with } assertionFileContentBuilder.append(LINE_SEPARATOR).append("}").append(LINE_SEPARATOR); @@ -354,10 +348,10 @@ private File createAssertionsFileFor(final Set classDescriptio private String generateAssertionEntryPointMethodsFor(final Set classDescriptionSet, Template assertionEntryPointMethodTemplate) { // sort ClassDescription according to their class name. - SortedSet sortedClassDescriptionSet = new TreeSet(classDescriptionSet); + SortedSet sortedClassDescriptionSet = new TreeSet<>(classDescriptionSet); // generate for each classDescription the entry point method, e.g. assertThat(MyClass) or then(MyClass) StringBuilder allAssertThatsContentBuilder = new StringBuilder(); - final String lineSeparator = System.getProperty("line.separator"); + final char lineSeparator = '\n'; for (ClassDescription classDescription : sortedClassDescriptionSet) { String assertionEntryPointMethodContent = assertionEntryPointMethodTemplate.getContent(); // resolve class assert (ex: PlayerAssert) @@ -374,7 +368,7 @@ private String generateAssertionEntryPointMethodsFor(final Set } private String determineBestEntryPointsAssertionsClassPackage(final Set classDescriptionSet) { - SortedSet packages = new TreeSet(new Comparator() { + SortedSet packages = new TreeSet<>(new Comparator() { @Override public int compare(final String o1, final String o2) { return o1.length() - o2.length(); @@ -389,18 +383,18 @@ public int compare(final String o1, final String o2) { } private static String assertClassNameOf(ClassDescription classDescription) { - return assertClassNameOf(classDescription.getTypeName()); + return assertClassNameOf(classDescription.getType()); } - private static String assertClassNameOf(TypeName type) { - return type.getSimpleNameWithOuterClassNotSeparatedByDots() + ASSERT_CLASS_SUFFIX; + private static String assertClassNameOf(TypeToken type) { + return TypeUtil.getTypeNameWithoutDots(TypeUtil.getTypeDeclaration(type, false, false)) + ASSERT_CLASS_SUFFIX; } private static String abstractAssertClassNameOf(ClassDescription classDescription) { - return abstractAssertClassNameOf(classDescription.getTypeName()); + return abstractAssertClassNameOf(classDescription.getType()); } - private static String abstractAssertClassNameOf(TypeName type) { + private static String abstractAssertClassNameOf(TypeToken type) { return ABSTRACT_ASSERT_CLASS_PREFIX + assertClassNameOf(type); } @@ -419,70 +413,78 @@ private String getDirectoryPathCorrespondingToPackage(final String packageName) return targetBaseDirectory + File.separator + packageName.replace('.', File.separatorChar); } - private static String listNeededImports(Set typesToImport, String classPackage) { + private static String listNeededImports(Set typesToImport, String classPackage) { StringBuilder importsBuilder = new StringBuilder(); - for (TypeName type : typesToImport) { - if (!type.isPrimitive() && !type.belongsToJavaLangPackage() && !type.getPackageName().equals(classPackage)) { - importsBuilder.append(format(IMPORT_LINE, type, LINE_SEPARATOR)); + for (String type : typesToImport) { + try { + Class clazz = Class.forName(type); + if (!clazz.isPrimitive() && !TypeUtil.isJavaLangType(clazz) + && !TypeUtil.isInnerPackageOf(type, classPackage) && !Objects.equals(classPackage, type)) { + importsBuilder.append(format(IMPORT_LINE, type, LINE_SEPARATOR)); + } + } catch (ClassNotFoundException cfne) { + // continue iteration; } } return importsBuilder.toString(); } - protected String generateAssertionsForGettersOf(ClassDescription classDescription) { - return generateAssertionsForGetters(classDescription.getGettersDescriptions(), classDescription); + protected void generateAssertionsForGettersOf(StringBuilder contentBuilder, ClassDescription classDescription) { + generateAssertionsForGetters(contentBuilder, classDescription.getGettersDescriptions(), classDescription); } - protected String generateAssertionsForDeclaredGettersOf(ClassDescription classDescription) { - return generateAssertionsForGetters(classDescription.getDeclaredGettersDescriptions(), classDescription); + protected void generateAssertionsForDeclaredGettersOf(StringBuilder contentBuilder, ClassDescription classDescription) { + generateAssertionsForGetters(contentBuilder, classDescription.getDeclaredGettersDescriptions(), classDescription); } - protected String generateAssertionsForGetters(Set getters, ClassDescription classDescription) { - StringBuilder assertionsForGetters = new StringBuilder(); + protected void generateAssertionsForGetters(StringBuilder assertionsForGetters, Set getters, ClassDescription classDescription) { for (GetterDescription getter : getters) { String assertionContent = assertionContentForProperty(getter, classDescription); assertionsForGetters.append(assertionContent).append(LINE_SEPARATOR); } - return assertionsForGetters.toString(); } - protected String generateAssertionsForPublicFieldsOf(ClassDescription classDescription) { - return generateAssertionsForPublicFields(classDescription.getFieldsDescriptions(), classDescription); + protected void generateAssertionsForPublicFieldsOf(StringBuilder contentBuilder, ClassDescription classDescription) { + generateAssertionsForPublicFields(contentBuilder, classDescription.getFieldsDescriptions(), classDescription); } - protected String generateAssertionsForDeclaredPublicFieldsOf(ClassDescription classDescription) { - return generateAssertionsForPublicFields(classDescription.getDeclaredFieldsDescriptions(), classDescription); + protected void generateAssertionsForDeclaredPublicFieldsOf(StringBuilder contentBuilder, ClassDescription classDescription) { + generateAssertionsForPublicFields(contentBuilder, classDescription.getDeclaredFieldsDescriptions(), classDescription); } - protected String generateAssertionsForPublicFields(Set fields, ClassDescription classDescription) { - StringBuilder assertionsForPublicFields = new StringBuilder(); + protected void generateAssertionsForPublicFields(StringBuilder assertionsForPublicFields, Set fields, ClassDescription classDescription) { for (FieldDescription field : fields) { String assertionContent = assertionContentForField(field, classDescription); assertionsForPublicFields.append(assertionContent).append(LINE_SEPARATOR); } - return assertionsForPublicFields.toString(); } private String assertionContentForField(FieldDescription field, ClassDescription classDescription) { + final TypeToken owningType = field.getOwningType(); + final String fieldName = field.getName(); final String fieldNameCap = capitalize(field.getName()); - if (classDescription.getGettersDescriptions().contains(new GetterDescription(fieldName, "get" + fieldNameCap, - field.getTypeDescription(), - Collections. emptyList()))) { - return ""; + try { + Method m = owningType.getRawType().getMethod("get" + fieldNameCap); + if (classDescription.getGettersDescriptions().contains(new GetterDescription(fieldName, owningType, m))) { + return ""; + } + } catch (NoSuchMethodException nsme) { + // ignore it, let flow keep going } + String assertionContent = baseAssertionContentFor(field, classDescription); // we reuse template for properties to have consistent assertions for property and field but change the way we get // the value since it's a field and not a property: - assertionContent = assertionContent.replace("${getter}()", "${property}"); + assertionContent = assertionContent.replace("${getter}()", PROPERTY_WITH_LOWERCASE_FIRST_CHAR); // - remove also ${throws} and ${throws_javadoc} since it does not make any sense for a field assertionContent = remove(assertionContent, "${throws}"); assertionContent = remove(assertionContent, "${throws_javadoc}"); // replace ${Property} and ${property} by field name (starting with uppercase/lowercase) if (field.isPredicate()) { - assertionContent = assertionContent.replace("actual." + PREDICATE + "()", "actual." + field.getOriginalMember()); + assertionContent = assertionContent.replace("actual." + PREDICATE + "()", "actual." + field.getName()); assertionContent = assertionContent.replace(PREDICATE_FOR_JAVADOC, field.getPredicateForJavadoc()); assertionContent = assertionContent.replace(NEGATIVE_PREDICATE_FOR_JAVADOC, @@ -500,7 +502,7 @@ Collections. emptyList()))) { } assertionContent = replace(assertionContent, PROPERTY_WITH_UPPERCASE_FIRST_CHAR, fieldNameCap); assertionContent = replace(assertionContent, PROPERTY_SIMPLE_TYPE, - field.getTypeName()); + field.getTypeName(false, false)); assertionContent = replace(assertionContent, PROPERTY_ASSERT_TYPE, field.getAssertTypeName(classDescription.getPackageName())); assertionContent = replace(assertionContent, PROPERTY_TYPE, @@ -511,7 +513,7 @@ Collections. emptyList()))) { return assertionContent; } - static private final Set JAVA_KEYWORDS = new HashSet(); + static private final Set JAVA_KEYWORDS = new HashSet<>(); static { String[] keywords = new String[] { @@ -582,7 +584,7 @@ private String assertionContentForProperty(GetterDescription getter, ClassDescri assertionContent = declareExceptions(getter, assertionContent, classDescription); - String propertyName = getter.getPropertyName(); + String propertyName = getter.getName(); if (getter.isPredicate()) { assertionContent = assertionContent.replace(PREDICATE_FOR_JAVADOC, getter.getPredicateForJavadoc()); @@ -596,13 +598,13 @@ private String assertionContentForProperty(GetterDescription getter, ClassDescri getter.getNegativePredicateForErrorMessagePart1()); assertionContent = assertionContent.replace(NEGATIVE_PREDICATE_FOR_FOR_ERROR_MESSAGE_PART2, getter.getNegativePredicateForErrorMessagePart2()); - assertionContent = replace(assertionContent, PREDICATE, getter.getOriginalMember()); + assertionContent = replace(assertionContent, PREDICATE, getter.getOriginalMember().getName()); assertionContent = replace(assertionContent, PREDICATE_NEG, getter.getNegativePredicate()); } - assertionContent = replace(assertionContent, PROPERTY_GETTER_CALL, getter.getOriginalMember()); + assertionContent = replace(assertionContent, PROPERTY_GETTER_CALL, getter.getOriginalMember().getName()); assertionContent = replace(assertionContent, PROPERTY_WITH_UPPERCASE_FIRST_CHAR, capitalize(propertyName)); assertionContent = replace(assertionContent, PROPERTY_SIMPLE_TYPE, - getter.getTypeName()); + getter.getTypeName(false, false)); assertionContent = replace(assertionContent, PROPERTY_ASSERT_TYPE, getter.getAssertTypeName(classDescription.getPackageName())); assertionContent = replace(assertionContent, PROPERTY_TYPE, @@ -646,7 +648,7 @@ private String baseAssertionContentFor(DataDescription fieldOrProperty, ClassDes Type type = fieldOrProperty.isPrimitiveWrapperType() ? Type.HAS_FOR_CHARACTER : Type.HAS_FOR_CHAR; assertionContent = templateRegistry.getTemplate(type).getContent(); } else if (fieldOrProperty.isPrimitiveType()) { - // use case : boolean getFoo -> not a predicate, but a primitive type + // use case : boolean getFoo -> not a predicate, but a primitive valueType Type type = fieldOrProperty.isPrimitiveWrapperType() ? Type.HAS_FOR_PRIMITIVE_WRAPPER : Type.HAS_FOR_PRIMITIVE; assertionContent = templateRegistry.getTemplate(type).getContent(); } @@ -668,7 +670,7 @@ private Type determinePredicateType(final DataDescription fieldOrProperty, final private boolean hasAlreadyNegativePredicate(final DataDescription fieldOrProperty, final ClassDescription classDescription) { for (final GetterDescription getterDescription : classDescription.getGettersDescriptions()) { - if (getterDescription.getOriginalMember().equals(fieldOrProperty.getNegativePredicate())) return true; + if (getterDescription.getOriginalMember().getName().equals(fieldOrProperty.getNegativePredicate())) return true; } return false; } @@ -686,11 +688,11 @@ private String declareExceptions(GetterDescription getter, String assertionConte StringBuilder throwsClause = new StringBuilder(); StringBuilder throwsJavaDoc = new StringBuilder(); boolean first = true; - for (TypeName exception : getter.getExceptions()) { + for (TypeToken exception : getter.getExceptions()) { if (first) throwsClause.append("throws "); else throwsClause.append(", "); first = false; - String exceptionName = exception.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName()); + String exceptionName = TypeUtil.getFullyQualifiedTypeNameIfNeeded(exception, classDescription.getPackageName()); throwsClause.append(exceptionName); throwsJavaDoc.append(LINE_SEPARATOR).append(" * @throws ").append(exceptionName); throwsJavaDoc.append(" if actual.").append("${getter}() throws one."); @@ -703,14 +705,15 @@ private String declareExceptions(GetterDescription getter, String assertionConte } private void fillFile(String customAssertionContent, File assertionJavaFile) throws IOException { - try (FileWriter fileWriter = new FileWriter(assertionJavaFile)) { + try (FileWriter fileWriter = new FileWriter(assertionJavaFile, false)) { fileWriter.write(customAssertionContent); } } private File createFile(String fileContent, String fileName, String targetDirectory) throws IOException { File file = new File(targetDirectory, fileName); - file.createNewFile(); + checkState(file.createNewFile(), + "Could not create file: dir=%s, file=%s", targetDirectory, fileName); fillFile(fileContent, file); return file; } @@ -720,7 +723,8 @@ private static boolean noClassDescriptionsGiven(final Set clas } private static void buildTargetDirectory(String targetDirectory) { - new File(targetDirectory).mkdirs(); + checkState(new File(targetDirectory).mkdirs(), + "Could not create targetDirectory: %s", targetDirectory); } @Override diff --git a/src/main/java/org/assertj/assertions/generator/cli/AssertionGeneratorLauncher.java b/src/main/java/org/assertj/assertions/generator/cli/AssertionGeneratorLauncher.java index ddd8a654..d4b5ab02 100644 --- a/src/main/java/org/assertj/assertions/generator/cli/AssertionGeneratorLauncher.java +++ b/src/main/java/org/assertj/assertions/generator/cli/AssertionGeneratorLauncher.java @@ -12,25 +12,21 @@ */ package org.assertj.assertions.generator.cli; -import static com.google.common.collect.Sets.newLinkedHashSet; -import static org.assertj.assertions.generator.util.ClassUtil.collectClasses; - -import java.io.File; -import java.io.IOException; -import java.util.Set; - -import org.apache.commons.cli.BasicParser; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; +import com.google.common.reflect.TypeToken; +import org.apache.commons.cli.*; import org.assertj.assertions.generator.BaseAssertionGenerator; import org.assertj.assertions.generator.description.ClassDescription; import org.assertj.assertions.generator.description.converter.ClassToClassDescriptionConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import static com.google.common.collect.Sets.newLinkedHashSet; +import static org.assertj.assertions.generator.util.ClassUtil.collectClasses; + public class AssertionGeneratorLauncher { @@ -51,7 +47,7 @@ public static void main(String[] args) throws IOException { return; } - Set> classes = collectClasses(line.getArgs()); + Set> classes = collectClasses(line.getArgs()); if (line.hasOption('H')) { generateHierarchicalAssertions(classes); @@ -71,34 +67,34 @@ private static void printHelp(Options options) { help.printHelp(cmdLine, "Generate AssertJ-style assertions for the specified classes", options, "The list of classes can either be package names (which includes all packages in the class) or fully-qualified class names."); } - private static void generateHierarchicalAssertions(Set> classes) throws IOException { + private static void generateHierarchicalAssertions(Set> types) throws IOException { // Create a hashset of the classes for efficient lookup. - Set> classSet = newLinkedHashSet(classes); - logger.info("Generating hierarchical assertions for classes {}", classes); + Set> typeSet = newLinkedHashSet(types); + logger.info("Generating hierarchical assertions for classes {}", types); BaseAssertionGenerator customAssertionGenerator = new BaseAssertionGenerator(); - for (Class clazz : classes) { - logger.info("Generating hierarchical assertions for class : {}", clazz.getName()); - File[] customAssertionFiles = customAssertionGenerator.generateHierarchicalCustomAssertionFor(toClassDescription(clazz), classSet); - logger.info("Generated {} hierarchical assertions files -> {}, {}", clazz.getSimpleName(), + for (TypeToken type : types) { + logger.info("Generating hierarchical assertions for class : {}", type); + File[] customAssertionFiles = customAssertionGenerator.generateHierarchicalCustomAssertionFor(toClassDescription(type), typeSet); + logger.info("Generated {} hierarchical assertions files -> {}, {}", type, customAssertionFiles[0].getAbsolutePath(), customAssertionFiles[1].getAbsolutePath()); } } - private static void generateFlatAssertions(Set> classes) throws IOException { - logger.info("Generating assertions for classes {}", classes); + private static void generateFlatAssertions(Set> types) throws IOException { + logger.info("Generating assertions for types {}", types); BaseAssertionGenerator customAssertionGenerator = new BaseAssertionGenerator(); - for (Class clazz : classes) { - logger.info("Generating assertions for class : {}", clazz.getName()); - File customAssertionFile = customAssertionGenerator.generateCustomAssertionFor(toClassDescription(clazz)); - logger.info("Generated {} assertions file -> {}", clazz.getSimpleName(), + for (TypeToken type : types) { + logger.info("Generating assertions for class : {}", type); + File customAssertionFile = customAssertionGenerator.generateCustomAssertionFor(toClassDescription(type)); + logger.info("Generated {} assertions file -> {}", type, customAssertionFile.getAbsolutePath()); } } - private static ClassDescription toClassDescription(Class clazz) { - return classDescriptionConverter.convertToClassDescription(clazz); + private static ClassDescription toClassDescription(TypeToken type) { + return classDescriptionConverter.convertToClassDescription(type); } } diff --git a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java index d732a494..9ffbfe3b 100644 --- a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,7 +12,11 @@ */ package org.assertj.assertions.generator.description; +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.util.TypeUtil; + import java.util.Collection; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; @@ -29,40 +33,41 @@ public class ClassDescription implements Comparable { private Set fieldsDescriptions; private Set declaredGettersDescriptions; private Set declaredFieldsDescriptions; - private TypeName classTypeName; - private Class superType; + private TypeToken type; + private TypeToken superType; - public ClassDescription(TypeName typeName) { + public ClassDescription(TypeToken type) { super(); - this.classTypeName = typeName; - this.gettersDescriptions = new TreeSet(); - this.fieldsDescriptions = new TreeSet(); - this.declaredGettersDescriptions = new TreeSet(); - this.declaredFieldsDescriptions = new TreeSet(); + this.type = type; + this.superType = null; + this.gettersDescriptions = new TreeSet<>(); + this.fieldsDescriptions = new TreeSet<>(); + this.declaredGettersDescriptions = new TreeSet<>(); + this.declaredFieldsDescriptions = new TreeSet<>(); } public String getClassName() { - return classTypeName.getSimpleName(); + return type.getRawType().getName(); } public String getFullyQualifiedClassName() { - return classTypeName.getFullyQualifiedClassName(); + return TypeUtil.getTypeDeclaration(type, false, true); } - public TypeName getTypeName() { - return classTypeName; + public TypeToken getType() { + return type; } public String getClassNameWithOuterClass() { - return classTypeName.getSimpleNameWithOuterClass(); + return TypeUtil.getTypeDeclaration(type, false, false); } public String getClassNameWithOuterClassNotSeparatedByDots() { - return classTypeName.getSimpleNameWithOuterClassNotSeparatedByDots(); + return TypeUtil.getTypeNameWithoutDots(getClassNameWithOuterClass()); //classTypeName.getSimpleNameWithOuterClassNotSeparatedByDots(); } public String getPackageName() { - return classTypeName.getPackageName(); + return type.getRawType().getPackage().getName(); } public Set getGettersDescriptions() { @@ -99,7 +104,7 @@ public void addDeclaredFieldDescriptions(Set declaredFieldDesc @Override public String toString() { - return "ClassDescription [classTypeName=" + classTypeName + "]"; + return "ClassDescription [valueType=" + type + "]"; } @Override @@ -108,25 +113,28 @@ public boolean equals(final Object o) { if (!(o instanceof ClassDescription)) return false; final ClassDescription that = (ClassDescription) o; - if (classTypeName != null ? !classTypeName.equals(that.classTypeName) : that.classTypeName != null) return false; - return true; + return (Objects.equals(type, that.type)); } @Override public int hashCode() { - return classTypeName != null ? classTypeName.hashCode() : 0; + return Objects.hash(type); } @Override public int compareTo(ClassDescription o) { - return classTypeName.compareTo(o.classTypeName); + return type.getRawType().getName().compareTo(o.type.getRawType().getName()); } - public Class getSuperType() { + public TypeToken getSuperType() { return superType; } + @SuppressWarnings("unchecked") public void setSuperType(Class superType) { - this.superType = superType; + // TypeToken#getSupertype(..) checks to make sure it is a super type + if (superType != null) { + this.superType = type.getSupertype((Class)superType); + } } } diff --git a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java index bcf429f8..f0aaf935 100644 --- a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,17 +12,22 @@ */ package org.assertj.assertions.generator.description; -import static org.apache.commons.lang3.StringUtils.removeStart; -import static org.assertj.assertions.generator.util.ClassUtil.getNegativePredicateFor; -import static org.assertj.assertions.generator.util.ClassUtil.getPredicatePrefix; -import static org.assertj.assertions.generator.util.StringUtil.camelCaseToWords; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Ordering; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Primitives; +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.util.TypeUtil; +import java.lang.reflect.Member; import java.util.List; import java.util.Map; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Ordering; -import com.google.common.primitives.Ints; +import static org.apache.commons.lang3.StringUtils.removeStart; +import static org.assertj.assertions.generator.util.ClassUtil.getNegativePredicateFor; +import static org.assertj.assertions.generator.util.ClassUtil.getPredicatePrefix; +import static org.assertj.assertions.generator.util.StringUtil.camelCaseToWords; /** * base class to describe a field or a property/getter @@ -30,8 +35,8 @@ public abstract class DataDescription { protected final String name; - protected final String originalMember; - protected final TypeDescription typeDescription; + protected final Member originalMember; + protected final TypeToken valueType; public static final Map PREDICATE_PREFIXES_FOR_JAVADOC = new ImmutableMap.Builder().put("is", "is") @@ -39,13 +44,19 @@ public abstract class DataDescription { .put("was", "was") .put("wasNot", "was not") .put("can", "can") + .put("canBe", "can be") .put("cannot", "cannot") + .put("cannotBe", "cannot be") .put("should", "should") + .put("shouldBe", "should be") .put("shouldNot", "should not") + .put("shouldNotBe", "should not be") .put("has", "has") .put("doesNotHave", "does not have") .put("will", "will") + .put("willBe", "will be") .put("willNot", "will not") + .put("willNotBe", "will not be") .build(); public static final Map PREDICATE_PREFIXES_FOR_ERROR_MESSAGE_PART1 = @@ -54,13 +65,19 @@ public abstract class DataDescription { .put("was", "was") .put("wasNot", "was not") .put("can", "can") + .put("canBe", "can be") .put("cannot", "cannot") + .put("cannotBe", "cannot be") .put("should", "should") + .put("shouldBe", "should be") .put("shouldNot", "should not") + .put("shouldNotBe", "should not be") .put("has", "has") .put("doesNotHave", "does not have") .put("will", "will") + .put("willBe", "will be") .put("willNot", "will not") + .put("willNotBe", "will not be") .build(); public static final Map PREDICATE_PREFIXES_FOR_ERROR_MESSAGE_PART2 = @@ -69,13 +86,19 @@ public abstract class DataDescription { .put("was", "was not") .put("wasNot", "was") .put("can", "cannot") + .put("canBe", "is not") .put("cannot", "can") + .put("cannotBe", "is not") .put("should", "should not") + .put("shouldBe", "is not") .put("shouldNot", "should") + .put("shouldNotBe", "should be") .put("has", "does not have") .put("doesNotHave", "has") .put("will", "will not") + .put("willBe", "will not be") .put("willNot", "will") + .put("willNotBe", "will be") .build(); private static final Ordering BY_BIGGER_LENGTH_ORDERING = new Ordering() { @@ -85,92 +108,110 @@ public int compare(String left, String right) { } }; - public DataDescription(String name, String originalMember, TypeDescription typeDescription) { + DataDescription(String name, Member originalMember, TypeToken type) { super(); this.name = name; this.originalMember = originalMember; - this.typeDescription = typeDescription; + this.valueType = type; } public String getName() { return name; } - public String getOriginalMember() { + public Member getOriginalMember() { return originalMember; } - public TypeDescription getTypeDescription() { - return typeDescription; + public TypeToken getValueType() { + return valueType; } - public String getTypeName() { - return typeDescription.getSimpleNameWithOuterClass(); + /** + * Get the type of the value stored by the {@link #originalMember} + * @return + * @param isFQN Whether or not to get the fully qualified name + * @param asParameter if true, this will generate a type-name that is best for + * passing as a parameter, for example, for a {@link java.util.Collection Collection} + * this would return {@code Collection<? extends String>} instead of + * just {@code String} + */ + public String getTypeName(boolean isFQN, final boolean asParameter) { + return TypeUtil.getTypeDeclaration(valueType, false, isFQN); } public boolean isIterableType() { - return typeDescription.isIterable(); + return valueType.isSubtypeOf(Iterable.class); } public boolean isArrayType() { - return typeDescription.isArray(); + return valueType.isArray(); } public boolean isPrimitiveType() { - return typeDescription.isPrimitive(); + return valueType.isPrimitive(); } public boolean isRealNumberType() { - return typeDescription.isRealNumber(); + TypeToken unwrapped = valueType.unwrap(); + return unwrapped.isSubtypeOf(double.class) || unwrapped.isSubtypeOf(float.class); } public boolean isWholeNumberType() { - return typeDescription.isWholeNumber(); + TypeToken unwrapped = valueType.unwrap(); + return unwrapped.isSubtypeOf(int.class) || unwrapped.isSubtypeOf(long.class) + || unwrapped.isSubtypeOf(byte.class) || unwrapped.isSubtypeOf(short.class); } public boolean isCharType() { - return typeDescription.isChar(); + TypeToken unwrapped = valueType.unwrap(); + return unwrapped.isSubtypeOf(char.class); } public boolean isPrimitiveWrapperType() { - return typeDescription.isPrimitiveWrapper(); + return Primitives.isWrapperType(valueType.getRawType()); } public abstract boolean isPredicate(); public String getPredicate() { - return originalMember; + return originalMember.getName(); } public String getNegativePredicate() { - return getNegativePredicateFor(originalMember); + return getNegativePredicateFor(originalMember.getName()); } /** - * return the simple element type name if element type belongs to given the package and the fully qualified element - * type name otherwise. + * return the simple element valueType name if element valueType belongs to given the package and the fully qualified element + * valueType name otherwise. * * @param packageName typically the package of the enclosing Class - * @return the simple element type name if element type belongs to given the package and the fully qualified element - * type name otherwise. + * @return the simple element valueType name if element valueType belongs to given the package and the fully qualified element + * valueType name otherwise. */ public String getElementTypeName(String packageName) { - return typeDescription.getElementTypeName() == null ? null - : typeDescription.getElementTypeName().getFullyQualifiedTypeNameIfNeeded(packageName); + if (valueType.isArray()) { + return TypeUtil.getFullyQualifiedTypeNameIfNeeded(valueType.getComponentType(), packageName); + } else if (valueType.isSubtypeOf(Iterable.class)) { + TypeToken componentType = valueType.resolveType(Iterable.class.getTypeParameters()[0]); + return TypeUtil.getFullyQualifiedTypeNameIfNeeded(componentType, packageName); + } + + return null; } public String getElementAssertTypeName(String packageName) { - TypeName elementTypeName = typeDescription.getElementTypeName(); - return elementTypeName == null ? null - : elementTypeName.getAssertTypeName(packageName); + TypeToken elementType = valueType.getComponentType(); + return elementType == null ? null : TypeUtil.getAssertType(elementType, packageName); } public String getFullyQualifiedTypeNameIfNeeded(String packageName) { - return typeDescription.getFullyQualifiedTypeNameIfNeeded(packageName); + return TypeUtil.getTypeDeclarationWithinPackage(valueType, packageName, false); } public String getAssertTypeName(String packageName) { - return typeDescription.getAssertTypeName(packageName); + return TypeUtil.getAssertType(valueType, packageName); } public String getPredicateForJavadoc() { @@ -208,15 +249,47 @@ protected String readablePropertyName() { List prefixesSortedByBiggerLength = BY_BIGGER_LENGTH_ORDERING.immutableSortedCopy(PREDICATE_PREFIXES_FOR_JAVADOC.keySet()); for (String predicatePrefix : prefixesSortedByBiggerLength) { - if (originalMember.startsWith(predicatePrefix)) { + if (originalMember.getName().startsWith(predicatePrefix)) { // get rid of prefix - String propertyName = removeStart(originalMember, predicatePrefix); + String propertyName = removeStart(originalMember.getName(), predicatePrefix); // make it human readable return camelCaseToWords(propertyName); } } + // should not arrive here ! return for best effort. return name; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DataDescription that = (DataDescription) o; + return Objects.equal(name, that.name) && + Objects.equal(originalMember, that.originalMember) && + Objects.equal(valueType, that.valueType); + } + + @Override + public int hashCode() { + return Objects.hashCode(name, originalMember, valueType); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[name=" + getName() + + ", valueType=" + valueType + + ", member=" + originalMember + "]"; + } + + protected int compareTo(final DataDescription other) { + // Use the property name to remove duplicates + int cmp = getName().compareTo(other.getName()); + if (cmp == 0) { + cmp = getOriginalMember().getName().compareTo(other.getOriginalMember().getName()); + } + + return cmp; + } } \ No newline at end of file diff --git a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java index 16c78397..73a78c11 100644 --- a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,6 +12,12 @@ */ package org.assertj.assertions.generator.description; +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.util.ClassUtil; +import org.assertj.assertions.generator.util.TypeUtil; + +import java.lang.reflect.Field; + import static org.apache.commons.lang3.StringUtils.capitalize; @@ -28,7 +34,7 @@ * need to know : *
    *
  • the field name, here "age"
  • - *
  • the field type
  • + *
  • the field valueType
  • *
* This class is immutable. * @@ -36,35 +42,42 @@ */ public class FieldDescription extends DataDescription implements Comparable { - public FieldDescription(String name, TypeDescription typeDescription) { - super(name, name, typeDescription); + private final TypeToken owningType; + + public FieldDescription(Field field, TypeToken owningType) { + super(ClassUtil.propertyNameOf(field), field, owningType.resolveType(field.getGenericType())); + + this.owningType = owningType; } @Override public int compareTo(FieldDescription other) { - return getName().compareTo(other.getName()); + return super.compareTo(other); } - + @Override - public String toString() { - return "FieldDescription[name=" + getName() + ", typeDescription=" + typeDescription + "]"; + public Field getOriginalMember() { + return (Field) super.getOriginalMember(); } @Override public boolean isPredicate() { - return typeDescription.isBoolean(); + return TypeUtil.isBoolean(valueType); } @Override public String getPredicate() { - final String retval = super.getNegativePredicate(); - return retval == null ? "is" + capitalize(originalMember) : originalMember; + final String retval = super.getNegativePredicate(); + return retval == null ? "is" + capitalize(originalMember.getName()) : originalMember.getName(); } @Override public String getNegativePredicate() { - final String retval = super.getNegativePredicate(); - return retval == null ? "isNot" + capitalize(originalMember) : retval; + final String retval = super.getNegativePredicate(); + return retval == null ? "isNot" + capitalize(originalMember.getName()) : retval; } + public TypeToken getOwningType() { + return owningType; + } } diff --git a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java index 1e767d96..b13ba173 100644 --- a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,10 +12,13 @@ */ package org.assertj.assertions.generator.description; -import java.util.ArrayList; -import java.util.List; - +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.Invokable; +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.util.ClassUtil; +import org.assertj.assertions.generator.util.TypeUtil; + +import java.lang.reflect.Method; /** * Stores the information needed to generate an assertion for a getter method. @@ -30,7 +33,7 @@ * need to know : *
    *
  • the property name, here "age"
  • - *
  • property type
  • + *
  • property valueType
  • *
* Note that Person doesn't need to have an age field, just the getAge method. *

@@ -40,35 +43,36 @@ */ public class GetterDescription extends DataDescription implements Comparable { - private final List exceptions; + private final Invokable invokable; + private final ImmutableList> exceptions; - public GetterDescription(String propertyName, String origMethodName, TypeDescription typeDescription, - List exceptions) { - super(propertyName, origMethodName, typeDescription); - this.exceptions = new ArrayList(exceptions); - } + public GetterDescription(String propertyName, TypeToken owningType, Method method) { + super(propertyName, method, owningType.method(method).getReturnType()); - public String getPropertyName() { - return getName(); + this.invokable = owningType.method(method); + this.exceptions = invokable.getExceptionTypes(); } @Override - public int compareTo(GetterDescription other) { - return getOriginalMember().compareTo(other.getOriginalMember()); + public Method getOriginalMember() { + return (Method) super.getOriginalMember(); } @Override - public String toString() { - return "GetterDescription [propertyName=" + getName() + ", typeDescription=" + typeDescription + "]"; + public int compareTo(GetterDescription other) { + return super.compareTo(other); } - public List getExceptions() { + public ImmutableList> getExceptions() { return exceptions; } @Override public boolean isPredicate() { - return typeDescription.isBoolean() && ClassUtil.isValidPredicateName(originalMember); + return TypeUtil.isBoolean(valueType) && ClassUtil.isValidPredicateName(originalMember.getName()); } + public Invokable getInvokable() { + return invokable; + } } diff --git a/src/main/java/org/assertj/assertions/generator/description/TypeDescription.java b/src/main/java/org/assertj/assertions/generator/description/TypeDescription.java deleted file mode 100644 index 67186ae8..00000000 --- a/src/main/java/org/assertj/assertions/generator/description/TypeDescription.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * 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-2015 the original author or authors. - */ -package org.assertj.assertions.generator.description; - -/** - * Stores the information needed to generate an assertion for a field or a getter method, and data related to the field - * or getter returned type (mostly to import needed classes). - *

- * We need to know : - *

    - *
  • the type
  • - *
  • the involved generic types
  • - *
  • the component type in case of property is an array
  • - *
- *

- * For example, let's say we have the following method in class Team : - * - *

- * public List<Player> getPlayers()
- * 
- * - * To generate the following assertion : - * - *
- * TeamAssert hasPlayers(Player... expectedPlayers)
- * 
- * - * we need to know the generic type of players property : Player. - *

- * - * @author Joel Costigliola - * - */ -public class TypeDescription { - - private TypeName typeName; - private boolean isArray; - private boolean isIterable; - // for array or iterable types only - private TypeName elementTypeName; - - public TypeDescription(TypeName typeName) { - super(); - if (typeName == null) throw new IllegalArgumentException("typeName must not be null."); - this.typeName = typeName; - this.isArray = false; - this.isIterable = false; - this.elementTypeName = null; - } - - public String getSimpleNameWithOuterClass() { - return typeName.getSimpleNameWithOuterClass(); - } - - public boolean isArray() { - return isArray; - } - - public void setArray(boolean isArray) { - this.isArray = isArray; - } - - public boolean isPrimitive() { - return typeName.isPrimitive(); - } - - public boolean isRealNumber() { - return typeName.isRealNumber(); - } - - public boolean isWholeNumber() { - return typeName.isWholeNumber(); - } - - public boolean isBoolean() { - return typeName.isBoolean(); - } - - public boolean isChar() { - return typeName.isChar(); - } - - public boolean isPrimitiveWrapper() { - return typeName.isPrimitiveWrapper(); - } - - public TypeName getElementTypeName() { - return elementTypeName; - } - - public void setElementTypeName(TypeName elementTypeName) { - this.elementTypeName = elementTypeName; - } - - public boolean isIterable() { - return isIterable; - } - - public void setIterable(boolean isIterable) { - this.isIterable = isIterable; - } - - @Override - public String toString() { - return "TypeDescription[typeName=" + typeName + ", array=" + isArray + ", iterable=" + isIterable + ", primitive=" - + isPrimitive() + ", boolean=" + isBoolean() + ", elementTypeName=" + elementTypeName + "]"; - } - - public String getFullyQualifiedTypeNameIfNeeded(String packageName) { - return typeName.getFullyQualifiedTypeNameIfNeeded(packageName); - } - - public String getAssertTypeName(String packageName) { - if (typeName == null) { - return null; - } - return typeName.getAssertTypeName(packageName); - } -} diff --git a/src/main/java/org/assertj/assertions/generator/description/TypeName.java b/src/main/java/org/assertj/assertions/generator/description/TypeName.java deleted file mode 100644 index 4662c3cc..00000000 --- a/src/main/java/org/assertj/assertions/generator/description/TypeName.java +++ /dev/null @@ -1,235 +0,0 @@ -/** - * 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-2015 the original author or authors. - */ -package org.assertj.assertions.generator.description; - -import static com.google.common.base.Objects.equal; -import static org.apache.commons.lang3.ArrayUtils.contains; -import static org.apache.commons.lang3.StringUtils.indexOfAny; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.apache.commons.lang3.StringUtils.remove; -import static org.apache.commons.lang3.StringUtils.substringAfterLast; -import static org.apache.commons.lang3.StringUtils.substringBefore; - -import org.assertj.assertions.generator.util.ClassUtil; - -/** - * Describes a type with package and class/interface simple name. - *

- * {@link TypeName} is immutable. - */ -public class TypeName implements Comparable { - - private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - private static final String BOOLEAN = "boolean"; - private static final String BOOLEAN_WRAPPER = "Boolean"; - private static final String CHAR = "char"; - private static final String CHARRACTER = "Character"; - private static final String NO_PACKAGE = ""; - public static final String JAVA_LANG_PACKAGE = "java.lang"; - protected static final String[] PRIMITIVE_TYPES = { "int", "long", "short", "byte", "float", "double", "char", BOOLEAN }; - protected static final String[] REAL_NUMBERS_TYPES = { "float", "double"}; - protected static final String[] REAL_NUMBERS_WRAPPER_TYPES = { "Float", "Double" }; - protected static final String[] WHOLE_NUMBERS_TYPES = { "int", "long", "short", "byte" }; - protected static final String[] WHOLE_NUMBERS_WRAPPER_TYPES = { "Integer", "Long", "Short", "Byte" }; - - private String typeSimpleName; - private String typeSimpleNameWithOuterClass; - private String typeSimpleNameWithOuterClassNotSeparatedByDots; - private String packageName; - - public TypeName(String typeSimpleName, String packageName) { - if (typeSimpleName == null) throw new IllegalArgumentException("type simple name should not be null"); - this.typeSimpleName = typeSimpleName; - this.typeSimpleNameWithOuterClass = typeSimpleName; - this.typeSimpleNameWithOuterClassNotSeparatedByDots = typeSimpleName; - setPackageName(packageName); - } - - /** - * WARNING : does not work for nested class like com.books.Author.Name, - * @param typeName - */ - public TypeName(String typeName) { - if (isBlank(typeName)) throw new IllegalArgumentException("type name should not be blank or null"); - int indexOfClassName = indexOfAny(typeName, CAPITAL_LETTERS); - if (indexOfClassName > 0) { - this.typeSimpleNameWithOuterClass = typeName.substring(indexOfClassName); - setPackageName(remove(typeName, "." + typeSimpleNameWithOuterClass)); - } else { - // primitive type => no package - this.typeSimpleNameWithOuterClass = typeName; - setPackageName(NO_PACKAGE); - } - this.typeSimpleName = typeSimpleNameWithOuterClass.contains(".") ? - substringAfterLast(typeSimpleNameWithOuterClass, ".") : typeSimpleNameWithOuterClass; - this.typeSimpleNameWithOuterClassNotSeparatedByDots = remove(typeSimpleNameWithOuterClass, "."); - } - - public TypeName(Class clazz) { - super(); - this.typeSimpleName = clazz.getSimpleName(); - this.typeSimpleNameWithOuterClass = ClassUtil.getSimpleNameWithOuterClass(clazz); - this.typeSimpleNameWithOuterClassNotSeparatedByDots = ClassUtil.getSimpleNameWithOuterClassNotSeparatedByDots(clazz); - this.packageName = clazz.getPackage() == null ? NO_PACKAGE : clazz.getPackage().getName(); - } - - public String getSimpleName() { - return typeSimpleName; - } - - public String getSimpleNameWithOuterClass() { - return typeSimpleNameWithOuterClass; - } - - public String getSimpleNameWithOuterClassNotSeparatedByDots() { - return typeSimpleNameWithOuterClassNotSeparatedByDots; - } - - public String getPackageName() { - return packageName; - } - - private void setPackageName(String packageName) { - this.packageName = packageName == null ? NO_PACKAGE : packageName; - } - - public boolean isPrimitive() { - return contains(PRIMITIVE_TYPES, typeSimpleName) && isEmpty(packageName); - } - - public boolean isRealNumber() { - return isPrimitiveRealNumber() || isRealNumberWrapper(); - } - - public boolean isWholeNumber() { - return isPrimitiveWholeNumber() || isWholeNumberWrapper(); - } - private boolean isPrimitiveRealNumber() { - return contains(REAL_NUMBERS_TYPES, typeSimpleName) && isEmpty(packageName); - } - - private boolean isRealNumberWrapper() { - return contains(REAL_NUMBERS_WRAPPER_TYPES, typeSimpleName) && JAVA_LANG_PACKAGE.equals(packageName); - } - - private boolean isPrimitiveWholeNumber() { - return contains(WHOLE_NUMBERS_TYPES, typeSimpleName) && isEmpty(packageName); - } - - private boolean isWholeNumberWrapper() { - return contains(WHOLE_NUMBERS_WRAPPER_TYPES, typeSimpleName) && JAVA_LANG_PACKAGE.equals(packageName); - } - - public boolean isBoolean() { - return isPrimitiveBoolean() || isBooleanWrapper(); - } - - private boolean isPrimitiveBoolean() { - return BOOLEAN.equals(typeSimpleName) && isEmpty(packageName); - } - - private boolean isBooleanWrapper() { - return BOOLEAN_WRAPPER.equals(typeSimpleName) && JAVA_LANG_PACKAGE.equals(packageName); - } - - public boolean isChar() { - return isPrimitiveChar() || isCharacter(); - } - - private boolean isCharacter() { - return CHARRACTER.equals(typeSimpleName) && JAVA_LANG_PACKAGE.equals(packageName); - } - - private boolean isPrimitiveChar() { - return CHAR.equals(typeSimpleName) && isEmpty(packageName); - } - - public boolean belongsToJavaLangPackage() { - return JAVA_LANG_PACKAGE.equals(packageName); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((packageName == null) ? 0 : packageName.hashCode()); - result = prime * result + ((typeSimpleName == null) ? 0 : typeSimpleName.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - TypeName other = (TypeName) obj; - if (packageName == null) { - if (other.packageName != null) return false; - } else if (!packageName.equals(other.packageName)) return false; - if (typeSimpleName == null) { - if (other.typeSimpleName != null) return false; - } else if (!typeSimpleName.equals(other.typeSimpleName)) return false; - return true; - } - - @Override - public String toString() { - return getFullyQualifiedClassName(); - } - - @Override - public int compareTo(TypeName o) { - return getFullyQualifiedClassName().compareTo(o.getFullyQualifiedClassName()); - } - - public boolean isArray() { - return typeSimpleName.contains("[]"); - } - - public boolean isNested() { - return typeSimpleNameWithOuterClass.contains("."); - } - - public TypeName getOuterClassTypeName() { - if (!isNested()) return null; - return new TypeName(substringBefore(typeSimpleNameWithOuterClass, ".") , packageName); - } - - public String getFullyQualifiedClassName() { - return isEmpty(packageName) ? typeSimpleNameWithOuterClass : packageName + "." + typeSimpleNameWithOuterClass; - } - - public String getFullyQualifiedTypeNameIfNeeded(String targetPackage) { - return belongsToJavaLangPackage() || equal(targetPackage, packageName) ? getSimpleNameWithOuterClass() : getFullyQualifiedClassName(); - } - - public boolean isPrimitiveWrapper() { - return isWholeNumberWrapper() || isRealNumberWrapper() || isBooleanWrapper() || isCharacter(); - } - - // used to support navigation assertion https://github.com/joel-costigliola/assertj-assertions-generator/issues/67 - public String getAssertTypeName(String packageName) { - String fullName = getFullyQualifiedClassName(); - if (fullName.startsWith("java.")) { - // lets assume the name is an assertj wrapper - return "org.assertj.core.api." + getSimpleName() + "Assert"; - } else { - String prefix = fullName; - if (packageName != null && packageName.equals(getPackageName())) { - prefix = getSimpleName(); - } - return prefix + "Assert"; - } - } -} diff --git a/src/main/java/org/assertj/assertions/generator/description/converter/ClassDescriptionConverter.java b/src/main/java/org/assertj/assertions/generator/description/converter/ClassDescriptionConverter.java index 4c914858..d5349cea 100644 --- a/src/main/java/org/assertj/assertions/generator/description/converter/ClassDescriptionConverter.java +++ b/src/main/java/org/assertj/assertions/generator/description/converter/ClassDescriptionConverter.java @@ -18,7 +18,7 @@ * * General contract to convert an object to a {@link ClassDescription}. * - * @param the type to convert to {@link ClassDescription}. + * @param the valueType to convert to {@link ClassDescription}. * @author Joel Costigliola * */ diff --git a/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java b/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java index 32662247..53243213 100644 --- a/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java +++ b/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,34 +12,22 @@ */ package org.assertj.assertions.generator.description.converter; -import static org.apache.commons.lang3.StringUtils.remove; -import static org.assertj.assertions.generator.util.ClassUtil.declaredGetterMethodsOf; -import static org.assertj.assertions.generator.util.ClassUtil.declaredPublicFieldsOf; -import static org.assertj.assertions.generator.util.ClassUtil.getterMethodsOf; -import static org.assertj.assertions.generator.util.ClassUtil.inheritsCollectionOrIsIterable; -import static org.assertj.assertions.generator.util.ClassUtil.isArray; -import static org.assertj.assertions.generator.util.ClassUtil.nonStaticPublicFieldsOf; -import static org.assertj.assertions.generator.util.ClassUtil.propertyNameOf; +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.GenerateAssertion; +import org.assertj.assertions.generator.description.ClassDescription; +import org.assertj.assertions.generator.description.FieldDescription; +import org.assertj.assertions.generator.description.GetterDescription; import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; -import org.assertj.assertions.generator.GenerateAssertion; -import org.assertj.assertions.generator.description.ClassDescription; -import org.assertj.assertions.generator.description.FieldDescription; -import org.assertj.assertions.generator.description.GetterDescription; -import org.assertj.assertions.generator.description.TypeDescription; -import org.assertj.assertions.generator.description.TypeName; -import org.assertj.assertions.generator.util.ClassUtil; +import static com.google.common.base.Preconditions.checkArgument; +import static org.assertj.assertions.generator.util.ClassUtil.*; -public class ClassToClassDescriptionConverter implements ClassDescriptionConverter> { +public class ClassToClassDescriptionConverter implements ClassDescriptionConverter> { private final AnnotationConfiguration annotationConfiguration; @@ -51,50 +39,56 @@ public ClassToClassDescriptionConverter(AnnotationConfiguration annotationConfig this.annotationConfiguration = annotationConfiguration; } - public ClassDescription convertToClassDescription(Class clazz) { - ClassDescription classDescription = new ClassDescription(new TypeName(clazz)); - classDescription.addGetterDescriptions(getterDescriptionsOf(clazz)); - classDescription.addFieldDescriptions(fieldDescriptionsOf(clazz)); - classDescription.addDeclaredGetterDescriptions(declaredGetterDescriptionsOf(clazz)); - classDescription.addDeclaredFieldDescriptions(declaredFieldDescriptionsOf(clazz)); - classDescription.setSuperType(clazz.getSuperclass()); + @Override + public ClassDescription convertToClassDescription(TypeToken type) { + checkArgument(!type.getRawType().isLocalClass(), "Can not support Local class %s", type); + ClassDescription classDescription = new ClassDescription(type); + classDescription.addGetterDescriptions(getterDescriptionsOf(type)); + classDescription.addFieldDescriptions(fieldDescriptionsOf(type)); + classDescription.addDeclaredGetterDescriptions(declaredGetterDescriptionsOf(type)); + classDescription.addDeclaredFieldDescriptions(declaredFieldDescriptionsOf(type)); + classDescription.setSuperType(type.getRawType().getSuperclass()); return classDescription; } - private Set getterDescriptionsOf(Class clazz) { - return doGetterDescriptionsOf(getterMethodsOf(clazz, annotationConfiguration.includedAnnotations()), clazz); + public ClassDescription convertToClassDescription(Class clazz) { + checkArgument(!clazz.isLocalClass(), "Can not support Local class %s", clazz); + return convertToClassDescription(TypeToken.of(clazz)); + } + + private Set getterDescriptionsOf(TypeToken type) { + return doGetterDescriptionsOf(getterMethodsOf(type, annotationConfiguration.includedAnnotations()), type); } - private Set declaredGetterDescriptionsOf(Class clazz) { - return doGetterDescriptionsOf(declaredGetterMethodsOf(clazz, annotationConfiguration.includedAnnotations()), clazz); + private Set declaredGetterDescriptionsOf(TypeToken type) { + return doGetterDescriptionsOf(declaredGetterMethodsOf(type, annotationConfiguration.includedAnnotations()), type); } - private Set doGetterDescriptionsOf(Set getters, Class clazz) { + private Set doGetterDescriptionsOf(Set getters, TypeToken type) { Set getterDescriptions = new TreeSet<>(); for (Method getter : getters) { // ignore getDeclaringClass if Enum - if (isGetDeclaringClassEnumGetter(getter, clazz)) continue; - final TypeDescription typeDescription = getTypeDescription(getter); - final List exceptionTypeNames = getExceptionTypeNames(getter); + if (isGetDeclaringClassEnumGetter(getter, type.getRawType())) continue; + String propertyName = propertyNameOf(getter); - getterDescriptions.add(new GetterDescription(propertyName, getter.getName(), typeDescription, - exceptionTypeNames)); + + getterDescriptions.add(new GetterDescription(propertyName, type, getter)); } return getterDescriptions; } - private Set declaredFieldDescriptionsOf(Class clazz) { - return doFieldDescriptionsOf(declaredPublicFieldsOf(clazz)); + private Set declaredFieldDescriptionsOf(TypeToken type) { + return doFieldDescriptionsOf(type, declaredPublicFieldsOf(type)); } - private Set fieldDescriptionsOf(Class clazz) { - return doFieldDescriptionsOf(nonStaticPublicFieldsOf(clazz)); + private Set fieldDescriptionsOf(TypeToken type) { + return doFieldDescriptionsOf(type, nonStaticPublicFieldsOf(type)); } - private Set doFieldDescriptionsOf(List fields) { + private Set doFieldDescriptionsOf(TypeToken type, List fields) { Set fieldDescriptions = new TreeSet<>(); for (Field field : fields) { - fieldDescriptions.add(new FieldDescription(field.getName(), getTypeDescription(field))); + fieldDescriptions.add(new FieldDescription(field, type)); } return fieldDescriptions; } @@ -103,72 +97,4 @@ private boolean isGetDeclaringClassEnumGetter(final Method getter, final Class getExceptionTypeNames(final Method getter) { - List exceptions = new ArrayList<>(); - for (Class exception : getter.getExceptionTypes()) { - exceptions.add(new TypeName(exception)); - } - return exceptions; - } - - private TypeDescription getTypeDescription(Member member) { - final Class type = getTypeOf(member); - if (isArray(type)) return buildArrayTypeDescription(type); - // we are interested in collections and iterable but not subtype of Iterable that are not collection. - // e.g. java.file.nio.Path that implements Iterable but has no ParameterizedType (ex : Path.getParent() -> Path) - if (inheritsCollectionOrIsIterable(type)) return buildIterableTypeDescription(member, type); - // "simple" type - return new TypeDescription(new TypeName(type)); - } - - private TypeDescription buildIterableTypeDescription(Member member, final Class type) { - final TypeDescription typeDescription = new TypeDescription(new TypeName(type)); - typeDescription.setIterable(true); - if (methodReturnTypeHasNoParameterInfo(member)) { - // not a ParameterizedType, i.e. no parameter information => use Object as element type. - typeDescription.setElementTypeName(new TypeName(Object.class)); - return typeDescription; - } - ParameterizedType parameterizedType = getParameterizedTypeOf(member); - if (parameterizedType.getActualTypeArguments()[0] instanceof GenericArrayType) { - GenericArrayType genericArrayType = (GenericArrayType) parameterizedType.getActualTypeArguments()[0]; - typeDescription.setElementTypeName(new TypeName(genericArrayType.toString())); - return typeDescription; - } - // Due to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7151486, - // java 7 is not able to detect GenericArrayType correctly => let's use a different way to detect array - Class internalClass = ClassUtil.getClass(parameterizedType.getActualTypeArguments()[0]); - if (internalClass.isArray()) { - String componentTypeWithoutClassPrefix = remove(internalClass.getComponentType().toString(), "class "); - typeDescription.setElementTypeName(new TypeName(componentTypeWithoutClassPrefix + "[]")); - } else { - typeDescription.setElementTypeName(new TypeName(internalClass)); - } - return typeDescription; - } - - private static boolean methodReturnTypeHasNoParameterInfo(Member member) { - // java loose generic info if getter is overridden :( - return member instanceof Method && !(((Method) member).getGenericReturnType() instanceof ParameterizedType); - } - - private static Class getTypeOf(Member member) { - if (member instanceof Method) return ((Method) member).getReturnType(); - if (member instanceof Field) return ((Field) member).getType(); - throw new IllegalArgumentException("argument should be a Method or Field but was " + member.getClass()); - } - - private static ParameterizedType getParameterizedTypeOf(Member member) { - if (member instanceof Method) return (ParameterizedType) ((Method) member).getGenericReturnType(); - if (member instanceof Field) return (ParameterizedType) ((Field) member).getGenericType(); - throw new IllegalArgumentException("argument should be a Method or Field but was " + member.getClass()); - } - - private static TypeDescription buildArrayTypeDescription(final Class arrayType) { - final TypeDescription typeDescription = new TypeDescription(new TypeName(arrayType)); - typeDescription.setElementTypeName(new TypeName(arrayType.getComponentType())); - typeDescription.setArray(true); - return typeDescription; - } - } 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 3939c58b..e8e321a1 100644 --- a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,55 +12,38 @@ */ package org.assertj.assertions.generator.util; -import static com.google.common.collect.Sets.newLinkedHashSet; -import static java.lang.reflect.Modifier.isPublic; -import static java.lang.reflect.Modifier.isStatic; -import static org.apache.commons.lang3.StringUtils.uncapitalize; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.ClassPath; +import com.google.common.reflect.ClassPath.ClassInfo; +import com.google.common.reflect.TypeToken; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; +import java.lang.reflect.*; import java.net.URL; import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.ClassUtils; -import org.apache.commons.lang3.StringUtils; - -import com.google.common.collect.ImmutableSet; -import com.google.common.reflect.ClassPath; -import com.google.common.reflect.ClassPath.ClassInfo; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Sets.newLinkedHashSet; +import static java.lang.reflect.Modifier.isPublic; +import static java.lang.reflect.Modifier.isStatic; +import static org.apache.commons.lang3.StringUtils.uncapitalize; /** * Some utilities methods related to classes and packages. * * @author Joel Costigliola */ +@SuppressWarnings("WeakerAccess") public class ClassUtil { - public static final String IS_PREFIX = "is"; public static final String GET_PREFIX = "get"; private static final String CLASS_SUFFIX = ".class"; private static final Comparator GETTER_COMPARATOR = new Comparator() { @@ -74,7 +57,7 @@ public int compare(Method m1, Method m2) { * Call {@link #collectClasses(ClassLoader, String...)} with Thread.currentThread().getContextClassLoader() * */ - public static Set> collectClasses(String... classOrPackageNames) { + public static Set> collectClasses(String... classOrPackageNames) { return collectClasses(Thread.currentThread().getContextClassLoader(), classOrPackageNames); } @@ -90,10 +73,10 @@ public static Set> collectClasses(String... classOrPackageNames) { * @return the set of {@link Class}es found * @throws RuntimeException if any error occurs */ - public static Set> collectClasses(ClassLoader classLoader, String... classOrPackageNames) { - Set> classes = newLinkedHashSet(); + public static Set> collectClasses(ClassLoader classLoader, String... classOrPackageNames) { + Set> classes = newLinkedHashSet(); for (String classOrPackageName : classOrPackageNames) { - Class clazz = tryToLoadClass(classOrPackageName, classLoader); + TypeToken clazz = tryToLoadClass(classOrPackageName, classLoader); if (clazz != null) { classes.add(clazz); } else { @@ -112,12 +95,12 @@ public static Set> collectClasses(ClassLoader classLoader, String... cl * @return the list of Class found * @throws RuntimeException if any error occurs */ - private static Set> getClassesInPackage(String packageName, ClassLoader classLoader) { + private static Set> getClassesInPackage(String packageName, ClassLoader classLoader) { if (classLoader == null) { throw new IllegalArgumentException("Null class loader."); } // load classes from classpath file system, this won't load classes in jars - Set> packageClasses = getPackageClassesFromClasspathFiles(packageName, classLoader); + Set> packageClasses = getPackageClassesFromClasspathFiles(packageName, classLoader); // load classes from classpath jars try { packageClasses.addAll(getPackageClassesFromClasspathJars(packageName, classLoader)); @@ -127,16 +110,16 @@ private static Set> getClassesInPackage(String packageName, ClassLoader return packageClasses; } - private static Set> getPackageClassesFromClasspathJars(String packageName, ClassLoader classLoader) + private static Set> getPackageClassesFromClasspathJars(String packageName, ClassLoader classLoader) throws IOException { ImmutableSet classesInfo = ClassPath.from(classLoader).getTopLevelClassesRecursive(packageName); - Set> classesInPackage = new HashSet>(); + Set> classesInPackage = new HashSet<>(); for (ClassInfo classInfo : classesInfo) { - classesInPackage.add(classInfo.load()); + classesInPackage.add(TypeToken.of(classInfo.load())); } - Set> filteredClassesInPackage = new HashSet>(); - for (Class classFromJar : classesInPackage) { + Set> filteredClassesInPackage = new HashSet<>(); + for (TypeToken classFromJar : classesInPackage) { if (isClassCandidateToAssertionsGeneration(classFromJar)) { filteredClassesInPackage.add(classFromJar); } @@ -144,12 +127,12 @@ private static Set> getPackageClassesFromClasspathJars(String packageNa return filteredClassesInPackage; } - private static Set> getPackageClassesFromClasspathFiles(String packageName, ClassLoader classLoader) { + private static Set> getPackageClassesFromClasspathFiles(String packageName, ClassLoader classLoader) { try { String packagePath = packageName.replace('.', File.separatorChar); // Ask for all resources for the path Enumeration resources = classLoader.getResources(packagePath); - Set> classes = newLinkedHashSet(); + Set> classes = newLinkedHashSet(); while (resources.hasMoreElements()) { File directory = new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8")); if (directory.canRead()) { @@ -172,15 +155,17 @@ private static Set> getPackageClassesFromClasspathFiles(String packageN * @param directory directory where to look for classes * @param packageName package name corresponding to directory * @param classLoader used classloader - * @return - * @throws UnsupportedEncodingException + * @return Set of all of the types in the directory + * @throws UnsupportedEncodingException thrown by {@link URLDecoder#decode(String, String)} */ - private static Set> getClassesInDirectory(File directory, String packageName, ClassLoader classLoader) + private static Set> getClassesInDirectory(File directory, String packageName, ClassLoader classLoader) throws UnsupportedEncodingException { - Set> classes = newLinkedHashSet(); + Set> classes = new LinkedHashSet<>(); + // Capture all the .class files in this directory // Get the list of the files contained in the package File[] files = directory.listFiles(); + checkNotNull(files, "No files were present in directory: %s", directory); for (File currentFile : files) { String currentFileName = currentFile.getName(); if (isClass(currentFileName)) { @@ -188,7 +173,7 @@ private static Set> getClassesInDirectory(File directory, String packag try { // removes the .class extension String className = packageName + '.' + StringUtils.remove(currentFileName, CLASS_SUFFIX); - Class loadedClass = loadClass(className, classLoader); + TypeToken loadedClass = loadClass(className, classLoader); // we are only interested in public classes that are neither anonymous nor local if (isClassCandidateToAssertionsGeneration(loadedClass)) { classes.add(loadedClass); @@ -201,9 +186,11 @@ private static Set> getClassesInDirectory(File directory, String packag // It's another package String subPackageName = packageName + ClassUtils.PACKAGE_SEPARATOR + currentFileName; // Ask for all resources for the path - URL resource = classLoader.getResource(subPackageName.replace('.', File.separatorChar)); + String path = subPackageName.replace('.', File.separatorChar); + URL resource = classLoader.getResource(path); + checkNotNull(resource, "resource URL from package is null, package %s", path); File subDirectory = new File(URLDecoder.decode(resource.getPath(), "UTF-8")); - Set> classesForSubPackage = getClassesInDirectory(subDirectory, subPackageName, classLoader); + Set> classesForSubPackage = getClassesInDirectory(subDirectory, subPackageName, classLoader); classes.addAll(classesForSubPackage); } } @@ -214,16 +201,20 @@ private static Set> getClassesInDirectory(File directory, String packag * @param loadedClass * @return */ - private static boolean isClassCandidateToAssertionsGeneration(Class loadedClass) { - return loadedClass != null && isPublic(loadedClass.getModifiers()) && !loadedClass.isAnonymousClass() - && !loadedClass.isLocalClass(); + private static boolean isClassCandidateToAssertionsGeneration(TypeToken loadedClass) { + if (loadedClass == null) { + return false; + } + + Class raw = loadedClass.getRawType(); + return isPublic(raw.getModifiers()) && !raw.isAnonymousClass() && !raw.isLocalClass(); } private static boolean isClass(String fileName) { return fileName.endsWith(CLASS_SUFFIX); } - private static Class tryToLoadClass(String className, ClassLoader classLoader) { + private static TypeToken tryToLoadClass(String className, ClassLoader classLoader) { try { return loadClass(className, classLoader); } catch (ClassNotFoundException e) { @@ -231,8 +222,8 @@ private static Class tryToLoadClass(String className, ClassLoader classLoader } } - private static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { - return Class.forName(className, false, classLoader); + private static TypeToken loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { + return TypeToken.of(Class.forName(className, false, classLoader)); } /** @@ -248,18 +239,20 @@ private static Class loadClass(String className, ClassLoader classLoader) thr * isMostValuablePlayer -> mostValuablePlayer * * - * @param getter getter method to deduce property from. + * @param member getter method to deduce property from. * @return the property name of given getter method */ - public static String propertyNameOf(Method getter) { - String methodName = getter.getName(); - String prefixToRemove = isPredicate(getter) ? IS_PREFIX : GET_PREFIX; - int pos = methodName.indexOf(prefixToRemove); + public static String propertyNameOf(Member member) { + String memberName = member.getName(); + String predicatePrefix = getPredicatePrefix(memberName); + String prefixToRemove = predicatePrefix != null ? predicatePrefix : GET_PREFIX; + + int pos = memberName.indexOf(prefixToRemove); if (pos != StringUtils.INDEX_NOT_FOUND) { - String propertyWithCapitalLetter = methodName.substring(pos + prefixToRemove.length()); + String propertyWithCapitalLetter = memberName.substring(pos + prefixToRemove.length()); return uncapitalize(propertyWithCapitalLetter); } else { - return methodName; + return memberName; } } @@ -267,10 +260,6 @@ public static boolean inheritsCollectionOrIsIterable(Class returnType) { return Collection.class.isAssignableFrom(returnType) || Iterable.class.equals(returnType); } - public static boolean isArray(Class returnType) { - return returnType.isArray(); - } - public static boolean isStandardGetter(Method method) { return isValidStandardGetterName(method.getName()) && !Void.TYPE.equals(method.getReturnType()) @@ -323,17 +312,20 @@ public int compare(String o1, String o2) { { "is", "isNot" }, { "was", "wasNot" }, { "can", "cannot" }, + { "canBe", "cannotBe" }, { "should", "shouldNot" }, + { "shouldBe", "shouldNotBe" }, { "has", "doesNotHave" }, + { "willBe", "willNotBe" }, { "will", "willNot" }, }; StringBuilder pattern = new StringBuilder("^(?:get"); - Map map = new HashMap(); + Map map = new HashMap<>(); for (String[] pair : predicates) { map.put(pair[0], pair[1]); map.put(pair[1], pair[0]); } - TreeSet sort = new TreeSet(LONGEST_TO_SHORTEST); + TreeSet sort = new TreeSet<>(LONGEST_TO_SHORTEST); sort.addAll(map.keySet()); for (String prefix : sort) { pattern.append('|').append(prefix); @@ -367,21 +359,22 @@ public static String getNegativePredicateFor(String name) { return null; } - public static Set declaredGetterMethodsOf(Class clazz, Set> includeAnnotations) { + public static Set declaredGetterMethodsOf(TypeToken type, Set> includeAnnotations) { + Class clazz = type.getRawType(); boolean isClassAnnotated = containsAny(clazz.getDeclaredAnnotations(), includeAnnotations); return filterGetterMethods(clazz.getDeclaredMethods(), includeAnnotations, isClassAnnotated); } - public static Set getterMethodsOf(Class clazz, Set> includeAnnotations) { + public static Set getterMethodsOf(TypeToken type, Set> includeAnnotations) { + Class clazz = type.getRawType(); boolean isClassAnnotated = containsAny(clazz.getDeclaredAnnotations(), includeAnnotations); return filterGetterMethods(clazz.getMethods(), includeAnnotations, isClassAnnotated); } private static Set filterGetterMethods(Method[] methods, Set> includeAnnotations, boolean isClassAnnotated) { - Set getters = new TreeSet(GETTER_COMPARATOR); - for (int i = 0; i < methods.length; i++) { - Method method = methods[i]; + Set getters = new TreeSet<>(GETTER_COMPARATOR); + for (Method method : methods) { if (isPublic(method.getModifiers()) && isNotDefinedInObjectClass(method) && isGetter(method, includeAnnotations, isClassAnnotated)) { @@ -397,9 +390,9 @@ private static boolean isGetter(Method method, Set> includeAnnotations, || isAnnotated(method, includeAnnotations, isClassAnnotated); } - public static List nonStaticPublicFieldsOf(Class clazz) { - Field[] fields = clazz.getFields(); - List nonStaticPublicFields = new ArrayList(); + public static List nonStaticPublicFieldsOf(TypeToken type) { + Field[] fields = type.getRawType().getFields(); + List nonStaticPublicFields = new ArrayList<>(); for (Field field : fields) { if (isNotStaticPublicField(field)) { nonStaticPublicFields.add(field); @@ -408,9 +401,9 @@ public static List nonStaticPublicFieldsOf(Class clazz) { return nonStaticPublicFields; } - public static List declaredPublicFieldsOf(Class clazz) { - Field[] fields = clazz.getDeclaredFields(); - List nonStaticPublicFields = new ArrayList(); + public static List declaredPublicFieldsOf(TypeToken type) { + Field[] fields = type.getRawType().getDeclaredFields(); + List nonStaticPublicFields = new ArrayList<>(); for (Field field : fields) { if (isNotStaticPublicField(field)) { nonStaticPublicFields.add(field); @@ -429,15 +422,15 @@ private static boolean isNotDefinedInObjectClass(Method method) { } public static Set> getClassesRelatedTo(Type type) { - Set> classes = new HashSet>(); + Set> classes = new HashSet<>(); - // non generic type : just add current type. + // non generic valueType : just add current valueType. if (type instanceof Class) { classes.add((Class) type); return classes; } - // generic type : add current type and its parameter types + // generic valueType : add current valueType and its parameter types if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) { @@ -468,8 +461,7 @@ public static String getSimpleNameWithOuterClass(Class clazz) { if (isNotNestedClass(clazz)) { return clazz.getSimpleName(); } - String nestedClassName = null; - nestedClassName = clazz.getName(); + String nestedClassName = clazz.getName(); nestedClassName = nestedClassName.substring(clazz.getPackage().getName().length() + 1); nestedClassName = nestedClassName.replace('$', '.'); return nestedClassName; @@ -492,8 +484,7 @@ public static String getSimpleNameWithOuterClassNotSeparatedByDots(Class claz if (isNotNestedClass(clazz)) { return clazz.getSimpleName(); } - String nestedClassName = null; - nestedClassName = clazz.getName(); + String nestedClassName = clazz.getName(); nestedClassName = nestedClassName.substring(clazz.getPackage().getName().length() + 1); nestedClassName = StringUtils.remove(nestedClassName, '$'); return nestedClassName; @@ -504,9 +495,9 @@ private static boolean isNotNestedClass(Class clazz) { } /** - * Get the underlying class for a type, or null if the type is a variable type. + * Get the underlying class for a valueType, or null if the valueType is a variable valueType. * - * @param type the type + * @param type the valueType * @return the underlying class */ public static Class getClass(final Type type) { diff --git a/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java b/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java new file mode 100644 index 00000000..505dbb12 --- /dev/null +++ b/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java @@ -0,0 +1,240 @@ +/* + * 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-2015 the original author or authors. + */ +package org.assertj.assertions.generator.util; + +import com.google.common.base.Strings; +import com.google.common.reflect.TypeToken; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.apache.commons.lang3.StringUtils.indexOfAny; +import static org.apache.commons.lang3.StringUtils.remove; + +/** + * Includes useful utilities for types. + */ +public class TypeUtil { + + public static final Package JAVA_LANG_PACKAGE = Object.class.getPackage(); + + /** + * return the simple element valueType name if element valueType belongs to given the package and the fully qualified element + * valueType name otherwise. + * + * @param packageName typically the package of the enclosing Class + * @return the simple element valueType name if element valueType belongs to given the package and the fully qualified element + * valueType name otherwise. + */ + public static String getFullyQualifiedTypeNameIfNeeded(TypeToken type, String packageName) { + Package toCheck = Package.getPackage(packageName); + return getFullyQualifiedTypeNameIfNeeded(type, toCheck); + } + + /** + * return the simple element valueType name if element valueType belongs to given the package and the fully qualified element + * valueType name otherwise. + * + * @param toCheck typically the package of the enclosing Class + * @return the simple element valueType name if element valueType belongs to given the package and the fully qualified element + * valueType name otherwise. + */ + public static String getFullyQualifiedTypeNameIfNeeded(TypeToken type, Package toCheck) { + return getTypeDeclarationWithinPackage(type, (toCheck == null ? null : toCheck.getName()), false); + } + + public static boolean isInnerPackageOf(Package child, Package parent) { + return child != null && parent != null && child.getName().startsWith(parent.getName()); + + } + + public static boolean isInnerPackageOf(String childPackage, String parentPackage) { + checkArgument(!Strings.isNullOrEmpty(childPackage), "childPackage is null or empty"); + checkNotNull(parentPackage, "parentPackage is null or empty"); + + return childPackage.startsWith(parentPackage); + } + + + public static boolean isJavaLangType(TypeToken type) { + return type.isPrimitive() || type.isArray() || Objects.equals(JAVA_LANG_PACKAGE, type.getRawType().getPackage()); + } + + public static boolean isJavaLangType(Type type) { + return isJavaLangType(TypeToken.of(type)); + } + + + public static String getTypeDeclaration(TypeToken type, final boolean asParameter, boolean fullyQualified) { + StringBuilder bld = new StringBuilder(); + Class raw = type.getRawType(); + getTypeDeclaration(bld, (raw.getPackage() == null ? null : raw.getPackage().getName()), type, asParameter, fullyQualified); + return bld.toString(); + } + + /** + * Uses the package name as a "local package" and tries to discern whether or not to generate + * fully qualified names. + * @param type + * @param packageName + * @param asParameter + * @return + */ + public static String getTypeDeclarationWithinPackage(TypeToken type, String packageName, final boolean asParameter) { + + boolean reqFQN = !Objects.equals(packageName, JAVA_LANG_PACKAGE.getName()) + && (!type.isPrimitive() && !type.isArray() && !Objects.equals(packageName, type.getRawType().getPackage().getName())); + StringBuilder bld = new StringBuilder(); + getTypeDeclaration(bld, packageName, type, asParameter, reqFQN); + return bld.toString(); + } + + + public static void getTypeDeclaration(StringBuilder bld, String basePackage, TypeToken type, boolean asParameter, boolean fullyQualified) { + + Class raw = type.getRawType(); + + // Gotta do some special casing + if (type.isArray()) { + getTypeDeclaration(bld, basePackage, type.getComponentType(), asParameter, fullyQualified); + bld.append("[]"); + } else if (type.isPrimitive()) { + bld.append(raw.toString()); + } else { + // Now we have some types that could be generic, so we have to do more + // to serialize it to the declaration + + if (raw.isMemberClass()) { // inner class + TypeToken outerClass = type.resolveType(raw.getEnclosingClass()); + getTypeDeclaration(bld, basePackage, outerClass, asParameter, fullyQualified); + bld.append("."); + + } else { + // it's a normal class, so just append the package here if needed + if (fullyQualified && !isJavaLangType(type)) { + bld.append(type.getRawType().getPackage().getName()); + bld.append("."); + } + } + + bld.append(raw.getSimpleName()); + + if (raw.getTypeParameters().length > 0) { + bld.append("<"); + for (TypeVariable tv : raw.getTypeParameters()) { + TypeToken paramType = type.resolveType(tv); + Class rawParam = paramType.getRawType(); + + if (rawParam.equals(Object.class)) { + bld.append("?"); + } else { + if (asParameter && !rawParam.equals(Object.class) && tv.getBounds().length > 0) { + String typeString = StringUtils.removeAll(paramType.toString(), "capture#\\d+-of\\s+"); + typeString = typeString.replace("(\\?\\s+extends\\s+){2,}", "? extends "); + + if (!typeString.contains("?")) { + bld.append("? extends "); + } + + // fall through + } + + Package paramPackage = paramType.getRawType().getPackage(); + + getTypeDeclaration(bld, basePackage, paramType, asParameter, + fullyQualified + || ((paramPackage != null && !Objects.equals(basePackage, paramPackage.getName())) + && Objects.equals(paramPackage, raw.getPackage()))); + } + + bld.append(","); + } + + bld.deleteCharAt(bld.length() - 1); + bld.append(">"); + } + } + + } + + // used to support navigation assertion + // https://github.com/joel-costigliola/assertj-assertions-generator/issues/67 + public static String getAssertType(TypeToken type, String packageName) { + + Class raw = type.getRawType(); + Package typePackage = raw.getPackage(); + + if (isInnerPackageOf(typePackage, Package.getPackage("java"))) { + try { + String name = "org.assertj.core.api." + raw.getSimpleName() + "Assert"; + // try to get the class, if it exists, then we know its valid + Class.forName(name); + + return name; + } catch (ClassNotFoundException cfne) { + // it wasn't found, this means the class doesn't exist, so fall back + } + } + + String typeName = resolveTypeNameInPackage(type, packageName); + return typeName + "Assert"; + } + + public static String resolveTypeNameInPackage(TypeToken type, Package currentPackage) { + Class raw = type.getRawType(); + + if (Objects.equals(raw.getPackage(), currentPackage)) { + return raw.getSimpleName(); + } else { + return raw.getName(); + } + } + + public static String resolveTypeNameInPackage(TypeToken type, String currentPackage) { + return resolveTypeNameInPackage(type, + checkNotNull(Package.getPackage(currentPackage), + "Package %s does not exist", currentPackage)); + } + + public static String resolveTypeNameInPackage(String type, String currentPackage) { + if (type.startsWith(currentPackage)) { + return type.substring(currentPackage.length() + 1, type.length()); + } else { + return type; + } + } + + private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public static String getTypeNameWithoutDots(String typeName) { + int indexOfClassName = indexOfAny(typeName, CAPITAL_LETTERS); + final String typeSimpleNameWithOuterClass; + if (indexOfClassName > 0) { + typeSimpleNameWithOuterClass = typeName.substring(indexOfClassName); + } else { + // primitive valueType => no package + typeSimpleNameWithOuterClass = typeName; + } + + return remove(typeSimpleNameWithOuterClass, "."); + } + + public static boolean isBoolean(TypeToken type) { + TypeToken unwrapped = type.unwrap(); + return unwrapped.isSubtypeOf(boolean.class); + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 7b4df334..93c2bd4b 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,7 +1,7 @@ - %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n diff --git a/src/main/resources/templates/custom_hierarchical_assertion_class_template.txt b/src/main/resources/templates/custom_hierarchical_assertion_class_template.txt index a3860267..fe736afe 100644 --- a/src/main/resources/templates/custom_hierarchical_assertion_class_template.txt +++ b/src/main/resources/templates/custom_hierarchical_assertion_class_template.txt @@ -1,6 +1,5 @@ package ${package}; - /** * {@link ${class_to_assert}} specific assertions - Generated by CustomAssertionGenerator. * diff --git a/src/main/resources/templates/has_assertion_template.txt b/src/main/resources/templates/has_assertion_template.txt index 355eee5f..8a912372 100644 --- a/src/main/resources/templates/has_assertion_template.txt +++ b/src/main/resources/templates/has_assertion_template.txt @@ -11,7 +11,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check ${propertyType} actual${Property} = actual.${getter}(); if (!Objects.areEqual(actual${Property}, ${property_safe})) { diff --git a/src/main/resources/templates/has_assertion_template_for_char.txt b/src/main/resources/templates/has_assertion_template_for_char.txt index d5dd842e..2cd3e6ec 100644 --- a/src/main/resources/templates/has_assertion_template_for_char.txt +++ b/src/main/resources/templates/has_assertion_template_for_char.txt @@ -11,8 +11,8 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - - // check + + // check ${property} char matches ${propertyType} actual${Property} = actual.${getter}(); if (actual${Property} != ${property_safe}) { failWithMessage(assertjErrorMessage, actual, ${property_safe}, actual${Property}); diff --git a/src/main/resources/templates/has_assertion_template_for_character.txt b/src/main/resources/templates/has_assertion_template_for_character.txt index 355eee5f..8a912372 100644 --- a/src/main/resources/templates/has_assertion_template_for_character.txt +++ b/src/main/resources/templates/has_assertion_template_for_character.txt @@ -11,7 +11,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check ${propertyType} actual${Property} = actual.${getter}(); if (!Objects.areEqual(actual${Property}, ${property_safe})) { diff --git a/src/main/resources/templates/has_assertion_template_for_primitive.txt b/src/main/resources/templates/has_assertion_template_for_primitive.txt index d5dd842e..9d48c22c 100644 --- a/src/main/resources/templates/has_assertion_template_for_primitive.txt +++ b/src/main/resources/templates/has_assertion_template_for_primitive.txt @@ -11,7 +11,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check ${propertyType} actual${Property} = actual.${getter}(); if (actual${Property} != ${property_safe}) { diff --git a/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt b/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt index 355eee5f..8a912372 100644 --- a/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt +++ b/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt @@ -11,7 +11,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check ${propertyType} actual${Property} = actual.${getter}(); if (!Objects.areEqual(actual${Property}, ${property_safe})) { diff --git a/src/main/resources/templates/has_assertion_template_for_real_number.txt b/src/main/resources/templates/has_assertion_template_for_real_number.txt index 7532dcfb..07a5eb73 100644 --- a/src/main/resources/templates/has_assertion_template_for_real_number.txt +++ b/src/main/resources/templates/has_assertion_template_for_real_number.txt @@ -12,7 +12,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - // check + // check value for ${property} ${propertyType} actual${Property} = actual.${getter}(); if (actual${Property} != ${property_safe}) { failWithMessage(assertjErrorMessage, actual, ${property_safe}, actual${Property}); @@ -36,11 +36,11 @@ isNotNull(); ${propertyType} actual${Property} = actual.${getter}(); - + // overrides the default error message with a more explicit one String assertjErrorMessage = String.format("\nExpecting ${property}:\n <%s>\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actual${Property}, ${property_safe}, offset, Math.abs(${property_safe} - actual${Property})); - + // check Assertions.assertThat(actual${Property}).overridingErrorMessage(assertjErrorMessage).isCloseTo(${property_safe}, Assertions.within(offset)); diff --git a/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt b/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt index 49a85a3d..bdd95f7d 100644 --- a/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt +++ b/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt @@ -36,11 +36,11 @@ isNotNull(); ${propertyType} actual${Property} = actual.${getter}(); - + // overrides the default error message with a more explicit one String assertjErrorMessage = String.format("\nExpecting ${property}:\n <%s>\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actual${Property}, ${property_safe}, offset, Math.abs(${property_safe} - actual${Property})); - + // check Assertions.assertThat(actual${Property}).overridingErrorMessage(assertjErrorMessage).isCloseTo(${property_safe}, Assertions.within(offset)); diff --git a/src/main/resources/templates/has_assertion_template_for_whole_number.txt b/src/main/resources/templates/has_assertion_template_for_whole_number.txt index d5dd842e..9d48c22c 100644 --- a/src/main/resources/templates/has_assertion_template_for_whole_number.txt +++ b/src/main/resources/templates/has_assertion_template_for_whole_number.txt @@ -11,7 +11,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check ${propertyType} actual${Property} = actual.${getter}(); if (actual${Property} != ${property_safe}) { diff --git a/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt b/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt index 355eee5f..8a912372 100644 --- a/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt +++ b/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt @@ -11,7 +11,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check ${propertyType} actual${Property} = actual.${getter}(); if (!Objects.areEqual(actual${Property}, ${property_safe})) { diff --git a/src/main/resources/templates/has_elements_assertion_template_for_array.txt b/src/main/resources/templates/has_elements_assertion_template_for_array.txt index f114557b..5277a65d 100644 --- a/src/main/resources/templates/has_elements_assertion_template_for_array.txt +++ b/src/main/resources/templates/has_elements_assertion_template_for_array.txt @@ -11,7 +11,7 @@ // check that given ${elementType} varargs is not null. if (${property_safe} == null) failWithMessage("Expecting ${property} parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.${getter}()).contains(${property_safe}); @@ -32,7 +32,7 @@ // check that given ${elementType} varargs is not null. if (${property_safe} == null) failWithMessage("Expecting ${property} parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.${getter}()).containsOnly(${property_safe}); @@ -53,7 +53,7 @@ // check that given ${elementType} varargs is not null. if (${property_safe} == null) failWithMessage("Expecting ${property} parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.${getter}()).doesNotContain(${property_safe}); @@ -72,13 +72,12 @@ // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have ${property} but had :\n <%s>"; - - // check + + // check that it is not empty if (actual.${getter}().length > 0) { failWithMessage(assertjErrorMessage, actual, java.util.Arrays.toString(actual.${getter}())); } - + // return the current assertion for method chaining return ${myself}; } - \ No newline at end of file diff --git a/src/main/resources/templates/has_elements_assertion_template_for_iterable.txt b/src/main/resources/templates/has_elements_assertion_template_for_iterable.txt index 59befc5c..f3e42458 100644 --- a/src/main/resources/templates/has_elements_assertion_template_for_iterable.txt +++ b/src/main/resources/templates/has_elements_assertion_template_for_iterable.txt @@ -11,14 +11,14 @@ // check that given ${elementType} varargs is not null. if (${property_safe} == null) failWithMessage("Expecting ${property} parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.${getter}(), ${property_safe}); // return the current assertion for method chaining return ${myself}; } - + /** * Verifies that the actual ${class_to_assert}'s ${property} contains the given ${elementType} elements in Collection. * @param ${property_safe} the given elements that should be contained in actual ${class_to_assert}'s ${property}. @@ -34,7 +34,7 @@ failWithMessage("Expecting ${property} parameter not to be null."); return ${myself}; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.${getter}(), ${property_safe}.toArray()); @@ -54,7 +54,7 @@ // check that given ${elementType} varargs is not null. if (${property_safe} == null) failWithMessage("Expecting ${property} parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.${getter}(), ${property_safe}); @@ -77,7 +77,7 @@ failWithMessage("Expecting ${property} parameter not to be null."); return ${myself}; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.${getter}(), ${property_safe}.toArray()); @@ -98,7 +98,7 @@ // check that given ${elementType} varargs is not null. if (${property_safe} == null) failWithMessage("Expecting ${property} parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.${getter}(), ${property_safe}); @@ -122,7 +122,7 @@ failWithMessage("Expecting ${property} parameter not to be null."); return ${myself}; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.${getter}(), ${property_safe}.toArray()); @@ -141,13 +141,12 @@ // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have ${property} but had :\n <%s>"; - + // check if (actual.${getter}().iterator().hasNext()) { failWithMessage(assertjErrorMessage, actual, actual.${getter}()); } - + // return the current assertion for method chaining return ${myself}; } - \ No newline at end of file diff --git a/src/main/resources/templates/is_assertion_template.txt b/src/main/resources/templates/is_assertion_template.txt index d1b8ead8..86b1e1be 100644 --- a/src/main/resources/templates/is_assertion_template.txt +++ b/src/main/resources/templates/is_assertion_template.txt @@ -8,11 +8,11 @@ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is true if (!actual.${predicate}()) { failWithMessage("\nExpecting that actual ${class_to_assert} ${predicate_for_error_message_part1} but ${predicate_for_error_message_part2}."); } - + // return the current assertion for method chaining return ${myself}; } @@ -26,11 +26,11 @@ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is false if (actual.${predicate}()) { failWithMessage("\nExpecting that actual ${class_to_assert} ${negative_predicate_for_error_message_part1} but ${negative_predicate_for_error_message_part2}."); } - + // return the current assertion for method chaining return ${myself}; } \ No newline at end of file diff --git a/src/main/resources/templates/is_wrapper_assertion_template.txt b/src/main/resources/templates/is_wrapper_assertion_template.txt index 36d4ceb1..44ea0ed1 100644 --- a/src/main/resources/templates/is_wrapper_assertion_template.txt +++ b/src/main/resources/templates/is_wrapper_assertion_template.txt @@ -12,7 +12,7 @@ if (Objects.areEqual(Boolean.FALSE, actual.${predicate}())) { failWithMessage("\nExpecting that actual ${class_to_assert} ${predicate_for_error_message_part1} but ${predicate_for_error_message_part2}."); } - + // return the current assertion for method chaining return ${myself}; } @@ -30,7 +30,7 @@ if (Objects.areEqual(Boolean.TRUE, actual.${predicate}())) { failWithMessage("\nExpecting that actual ${class_to_assert} ${negative_predicate_for_error_message_part1} but ${negative_predicate_for_error_message_part2}."); } - + // return the current assertion for method chaining return ${myself}; } \ No newline at end of file diff --git a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java index c31daacb..7be3df13 100644 --- a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java +++ b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,17 +12,8 @@ */ package org.assertj.assertions.generator; -import org.assertj.assertions.generator.data.AnnotatedClass; -import org.assertj.assertions.generator.data.ArtWork; -import org.assertj.assertions.generator.data.AutoValue; -import org.assertj.assertions.generator.data.AutoValueAnnotatedClass; -import org.assertj.assertions.generator.data.BooleanPredicates; -import org.assertj.assertions.generator.data.FieldPropertyClash; -import org.assertj.assertions.generator.data.InterferencePrimitives; -import org.assertj.assertions.generator.data.Keywords; -import org.assertj.assertions.generator.data.Movie; -import org.assertj.assertions.generator.data.Primitives; -import org.assertj.assertions.generator.data.Team; +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.data.*; import org.assertj.assertions.generator.data.nba.Player; import org.assertj.assertions.generator.data.nba.PlayerAgent; import org.assertj.assertions.generator.description.ClassDescription; @@ -39,7 +30,9 @@ import java.io.File; import java.io.IOException; import java.sql.SQLException; +import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Set; import static com.google.common.collect.Sets.newHashSet; @@ -48,21 +41,20 @@ import static org.apache.commons.lang3.StringUtils.replace; import static org.assertj.assertions.generator.BaseAssertionGenerator.ABSTRACT_ASSERT_CLASS_PREFIX; import static org.assertj.assertions.generator.BaseAssertionGenerator.ASSERT_CLASS_FILE_SUFFIX; -import static org.assertj.assertions.generator.util.ClassUtil.collectClasses; -import static org.assertj.assertions.generator.util.ClassUtil.getSimpleNameWithOuterClass; -import static org.assertj.assertions.generator.util.ClassUtil.getSimpleNameWithOuterClassNotSeparatedByDots; +import static org.assertj.assertions.generator.util.ClassUtil.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.contentOf; @RunWith(Theories.class) public class AssertionGeneratorTest implements NestedClassesTest, BeanWithExceptionsTest { - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + private static final String LINE_SEPARATOR = "\n"; private static final String TARGET_DIRECTORY = "target"; private static final File RESOURCES_DIRECTORY = new File("src/test/resources"); private static final Logger logger = LoggerFactory.getLogger(AssertionGeneratorTest.class); private ClassToClassDescriptionConverter converter; private AssertionGenerator assertionGenerator; - private static final Set> allClasses = newHashSet(new Class[] { Movie.class, ArtWork.class }); + private static final Set> allClasses = + newHashSet(Arrays.>asList(TypeToken.of(Movie.class), TypeToken.of(ArtWork.class))); @Before public void beforeEachTest() throws IOException { @@ -108,7 +100,8 @@ public void should_generate_assertion_for_class_with_properties_that_clash_with_ @Test public void should_generate_assertion_for_class_with_predicates() throws Exception { - assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(BooleanPredicates.class)); + ClassDescription classDescription = converter.convertToClassDescription(BooleanPredicates.class); + assertionGenerator.generateCustomAssertionFor(classDescription); assertGeneratedAssertClass(BooleanPredicates.class, "BooleanPredicates.expected.txt"); } @@ -126,7 +119,7 @@ public void should_generate_assertion_for_class_with_interference_primitives() t @Test public void should_generate_flat_assertion_for_movie_class() throws Exception { - abstractFileGeneratedFor(Movie.class).delete(); + assertThat(abstractFileGeneratedFor(Movie.class).delete()).isTrue(); assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Movie.class)); assertGeneratedAssertClass(Movie.class, "MovieAssert.flat.expected.txt"); assertThat(abstractFileGeneratedFor(Movie.class)).doesNotExist(); @@ -165,16 +158,18 @@ public void should_generate_hierarchical_assertion_for_nested_class(NestedClass } @Theory - public void should_generate_assertion_for_property_with_exception(Class beanClass) throws Exception { - assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(beanClass)); + public void should_generate_assertion_for_property_with_exception(TypeToken beanType) throws Exception { + assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(beanType)); + Class clazz = beanType.getRawType(); String expectedContent = contentOf(new File(RESOURCES_DIRECTORY, "BeanWithOneException.expected.txt"), defaultCharset()); - if (!BEAN_WITH_ONE_EXCEPTION.equals(beanClass)) { - expectedContent = expectedContent.replace(BEAN_WITH_ONE_EXCEPTION.getSimpleName(), beanClass.getSimpleName()); + if (!BEAN_WITH_ONE_EXCEPTION.equals(beanType)) { + expectedContent = expectedContent.replace(BEAN_WITH_ONE_EXCEPTION.getRawType().getSimpleName(), clazz.getSimpleName()); expectedContent = expectedContent.replace(" throws java.io.IOException ", " throws java.io.IOException, java.sql.SQLException "); - GetterWithException[] getters = { STRING_1_EXCEPTION, BOOLEAN_1_EXCEPTION, ARRAY_1_EXCEPTION, - ITERABLE_1_EXCEPTION }; + List getters = Arrays.asList(STRING_1_EXCEPTION, BOOLEAN_1_EXCEPTION, ARRAY_1_EXCEPTION, + ITERABLE_1_EXCEPTION); + Collections.sort(getters); for (GetterWithException getter : getters) { String throwsClause = generateThrowsClause(IOException.class, getter.getPropertyName(), getter.isBooleanType()); String replacement = throwsClause @@ -183,13 +178,14 @@ public void should_generate_assertion_for_property_with_exception(Class beanC expectedContent = expectedContent.replace(throwsClause, replacement); } } - assertThat(fileGeneratedFor(beanClass)).hasContent(expectedContent); + assertThat(fileGeneratedFor(clazz)).hasContent(expectedContent); } @Test public void should_generate_assertion_for_classes_in_package() throws Exception { - Set> classes = collectClasses("org.assertj.assertions.generator.data"); - for (Class clazz : classes) { + Set> classes = collectClasses("org.assertj.assertions.generator.data"); + for (TypeToken type : classes) { + Class clazz = type.getRawType(); assertThat(clazz.isAnonymousClass()).as("check that <" + clazz.getSimpleName() + "> is not anonymous").isFalse(); assertThat(clazz.isLocalClass()).as("check that " + clazz.getSimpleName() + " is not local").isFalse(); assertThat(isPublic(clazz.getModifiers())).as("check that " + clazz.getSimpleName() + " is public").isTrue(); @@ -203,8 +199,9 @@ public void should_generate_assertion_for_classes_in_package() throws Exception @Test public void should_generate_assertion_for_classes_in_package_using_provided_class_loader() throws Exception { ClassLoader customClassLoader = new MyClassLoader(Thread.currentThread().getContextClassLoader()); - Set> classes = collectClasses(customClassLoader, "org.assertj.assertions.generator.data"); - for (Class clazz : classes) { + Set> types = collectClasses(customClassLoader, "org.assertj.assertions.generator.data"); + for (TypeToken type : types) { + Class clazz = type.getRawType(); assertThat(clazz.isAnonymousClass()).as("check that " + clazz.getSimpleName() + " is not anonymous").isFalse(); assertThat(clazz.isLocalClass()).as("check that " + clazz.getSimpleName() + " is not local").isFalse(); assertThat(isPublic(clazz.getModifiers())).as("check that " + clazz.getSimpleName() + " is public").isTrue(); diff --git a/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java b/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java index 1f31f02a..96d8a894 100644 --- a/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java +++ b/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java @@ -12,26 +12,7 @@ */ package org.assertj.assertions.generator; -import static com.google.common.collect.Sets.newLinkedHashSet; -import static org.assertj.assertions.generator.AssertionsEntryPointType.AUTO_CLOSEABLE_BDD_SOFT; -import static org.assertj.assertions.generator.AssertionsEntryPointType.AUTO_CLOSEABLE_SOFT; -import static org.assertj.assertions.generator.AssertionsEntryPointType.BDD; -import static org.assertj.assertions.generator.AssertionsEntryPointType.BDD_SOFT; -import static org.assertj.assertions.generator.AssertionsEntryPointType.JUNIT_BDD_SOFT; -import static org.assertj.assertions.generator.AssertionsEntryPointType.JUNIT_SOFT; -import static org.assertj.assertions.generator.AssertionsEntryPointType.SOFT; -import static org.assertj.assertions.generator.AssertionsEntryPointType.STANDARD; -import static org.assertj.assertions.generator.DefaultTemplateRegistryProducer.DEFAULT_ASSERTIONS_ENTRY_POINT_CLASS_TEMPLATE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.contentOf; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.data.ArtWork; import org.assertj.assertions.generator.data.Movie; import org.assertj.assertions.generator.data.Name; @@ -43,6 +24,18 @@ import org.assertj.assertions.generator.data.nba.Team; import org.assertj.assertions.generator.description.ClassDescription; import org.assertj.assertions.generator.description.converter.ClassToClassDescriptionConverter; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import static com.google.common.collect.Sets.newLinkedHashSet; +import static org.assertj.assertions.generator.AssertionsEntryPointType.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.contentOf; public class AssertionsEntryPointGeneratorTest { private static final String TARGET_DIRECTORY = "target"; @@ -269,7 +262,7 @@ private Set getClassDescriptionsOf(Class... classes) { Set classDescriptionSet = new LinkedHashSet<>(classes.length); ClassToClassDescriptionConverter converter = new ClassToClassDescriptionConverter(); for (Class clazz : classes) { - classDescriptionSet.add(converter.convertToClassDescription(clazz)); + classDescriptionSet.add(converter.convertToClassDescription(TypeToken.of(clazz))); } return classDescriptionSet; } diff --git a/src/test/java/org/assertj/assertions/generator/BeanWithExceptionsTest.java b/src/test/java/org/assertj/assertions/generator/BeanWithExceptionsTest.java index a09c0dce..498c63fb 100644 --- a/src/test/java/org/assertj/assertions/generator/BeanWithExceptionsTest.java +++ b/src/test/java/org/assertj/assertions/generator/BeanWithExceptionsTest.java @@ -12,79 +12,84 @@ */ package org.assertj.assertions.generator; +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.data.BeanWithOneException; import org.assertj.assertions.generator.data.BeanWithTwoExceptions; -import org.assertj.assertions.generator.description.TypeName; - import org.junit.experimental.theories.DataPoint; import java.io.IOException; import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; /** * This interface contains a set of constants for testing generation from {@link org.assertj.assertions.generator.data.BeanWithOneException} class. */ public interface BeanWithExceptionsTest { - static final Class[] ONE_EXCEPTION = new Class[]{IOException.class}; - static final Class[] TWO_EXCEPTIONS = new Class[]{IOException.class, SQLException.class}; - + List> ONE_EXCEPTION = + ImmutableList.>of(TypeToken.of(IOException.class)); + List> TWO_EXCEPTIONS = + ImmutableList.>of(TypeToken.of(IOException.class), + TypeToken.of(SQLException.class)); @DataPoint - public static final Class BEAN_WITH_ONE_EXCEPTION = BeanWithOneException.class; + TypeToken BEAN_WITH_ONE_EXCEPTION = TypeToken.of(BeanWithOneException.class); @DataPoint - public static final Class BEAN_WITH_TWO_EXCEPTIONS = BeanWithTwoExceptions.class; + TypeToken BEAN_WITH_TWO_EXCEPTIONS = TypeToken.of(BeanWithTwoExceptions.class); @DataPoint - public static final GetterWithException STRING_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "stringPropertyThrowsException", ONE_EXCEPTION, false); + GetterWithException STRING_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "stringPropertyThrowsException", ONE_EXCEPTION, false); @DataPoint - public static final GetterWithException STRING_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "stringPropertyThrowsException", TWO_EXCEPTIONS, false); + GetterWithException STRING_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "stringPropertyThrowsException", TWO_EXCEPTIONS, false); @DataPoint - public static final GetterWithException BOOLEAN_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "booleanPropertyThrowsException", ONE_EXCEPTION, true); + GetterWithException BOOLEAN_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "booleanPropertyThrowsException", ONE_EXCEPTION, true); @DataPoint - public static final GetterWithException BOOLEAN_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "booleanPropertyThrowsException", TWO_EXCEPTIONS, true); + GetterWithException BOOLEAN_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "booleanPropertyThrowsException", TWO_EXCEPTIONS, true); @DataPoint - public static final GetterWithException ARRAY_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "arrayPropertyThrowsException", ONE_EXCEPTION, false); + GetterWithException ARRAY_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "arrayPropertyThrowsException", ONE_EXCEPTION, false); @DataPoint - public static final GetterWithException ARRAY_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "arrayPropertyThrowsException", TWO_EXCEPTIONS, false); + GetterWithException ARRAY_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "arrayPropertyThrowsException", TWO_EXCEPTIONS, false); @DataPoint - public static final GetterWithException ITERABLE_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "iterablePropertyThrowsException", ONE_EXCEPTION, false); + GetterWithException ITERABLE_1_EXCEPTION = new GetterWithException(BEAN_WITH_ONE_EXCEPTION, "iterablePropertyThrowsException", ONE_EXCEPTION, false); @DataPoint - public static final GetterWithException ITERABLE_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "iterablePropertyThrowsException", TWO_EXCEPTIONS, false); + GetterWithException ITERABLE_2_EXCEPTIONS = new GetterWithException(BEAN_WITH_TWO_EXCEPTIONS, "iterablePropertyThrowsException", TWO_EXCEPTIONS, false); - public static class GetterWithException { - private final Class beanClass; + class GetterWithException implements Comparable { + private final TypeToken beanClass; private final String propertyName; - private final List exceptions; + private final List> exceptions; private final boolean booleanType; - public GetterWithException(Class beanClass, String propertyName, Class[] exceptions, boolean booleanType) { + public GetterWithException(TypeToken beanClass, + String propertyName, + List> exceptions, + boolean booleanType) { this.beanClass = beanClass; this.propertyName = propertyName; this.booleanType = booleanType; - List list = new ArrayList(exceptions.length); - for (Class exception : exceptions) { - list.add(new TypeName(exception)); - } - this.exceptions = list; + this.exceptions = exceptions; } public String getPropertyName() { return propertyName; } - public TypeName[] getExceptions() { - return exceptions.toArray(new TypeName[exceptions.size()]); + public List> getExceptions() { + return exceptions; } - public Class getBeanClass() { + public TypeToken getBeanClass() { return beanClass; } public boolean isBooleanType() { return booleanType; } + + @Override + public int compareTo(GetterWithException o) { + return propertyName.compareTo(o.propertyName); + } } } diff --git a/src/test/java/org/assertj/assertions/generator/data/Keywords.java b/src/test/java/org/assertj/assertions/generator/data/Keywords.java index 0bed7725..a98377bc 100644 --- a/src/test/java/org/assertj/assertions/generator/data/Keywords.java +++ b/src/test/java/org/assertj/assertions/generator/data/Keywords.java @@ -23,6 +23,7 @@ public class Keywords { public String getAbstract() throws java.io.IOException { return null; } + public Object getAssert() { return null; } 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 29ddabe0..90441c4f 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 @@ -12,32 +12,39 @@ */ package org.assertj.assertions.generator.data.nba; -import static java.lang.String.format; -import static org.assertj.core.util.Objects.areEqual; +import org.assertj.assertions.generator.data.Name; import java.util.ArrayList; import java.util.List; -import org.assertj.assertions.generator.data.Name; +import static java.lang.String.format; +import static org.assertj.core.util.Objects.areEqual; /** * @author Joel Costigliola */ +@SuppressWarnings("unused") public class Player { private Name name; private boolean rookie; private int pointsPerGame; + private Integer pointerPerGameWrapped; private int assistsPerGame; private int reboundsPerGame; private String team; private float size; + private Float sizeAsFloatWrapper; + private double sizeDouble; + private Double sizeAsDoubleWrapper; // boolean property to test #46 private boolean isDisabled; private List teamMates = new ArrayList(); private List points = new ArrayList(); private String[] previousTeams = {}; + private boolean bad; + public Player(Name name, String team) { setName(name); setTeam(team); @@ -111,6 +118,38 @@ public boolean isRookie() { return rookie; } + public boolean wasRookie() { + return rookie; + } + + public boolean shouldWin() { + return false; + } + + public boolean canWin() { + return false; + } + + public boolean willWin() { + return false; + } + + public boolean cannotWin() { + return !canWin(); + } + + public boolean hasTrophy() { + return false; + } + + public boolean doesNotHaveFun() { + return false; + } + + public boolean shouldNotPlay() { + return false; + } + public void setRookie(boolean rookie) { this.rookie = rookie; } diff --git a/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java b/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java index 64ee11f3..f23182ca 100644 --- a/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java +++ b/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,87 +12,76 @@ */ package org.assertj.assertions.generator.description; -import static org.assertj.core.api.Assertions.assertThat; - +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.data.Name; import org.assertj.assertions.generator.data.nba.Player; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + public class FieldDescriptionTest { - private DataDescription fieldDescription; - private TypeDescription boolDesc; + private static final TypeToken PLAYER_TYPE = TypeToken.of(Player.class); + private FieldDescription fieldDescription; @Test - public void should_create_valid_typename_from_class() { - fieldDescription = new FieldDescription("bestPlayer", new TypeDescription(new TypeName(Player.class))); - assertThat(fieldDescription.getName()).isEqualTo("bestPlayer"); - assertThat(fieldDescription.getTypeName()).isEqualTo("Player"); + public void should_create_valid_typename_from_class() throws Exception { + fieldDescription = new FieldDescription(Player.class.getDeclaredField("name"), PLAYER_TYPE); + assertThat(fieldDescription.getName()).isEqualTo("name"); + assertThat(fieldDescription.getTypeName(false, false)).isEqualTo(Name.class.getSimpleName()); assertThat(fieldDescription.getElementTypeName(Player.class.getPackage().getName())).isNull(); - boolDesc = new TypeDescription(new TypeName(boolean.class)); } @Test - public void should_show_information_in_toString() { - fieldDescription = new FieldDescription("bestPlayer", new TypeDescription(new TypeName(Player.class))); - assertThat(fieldDescription.toString()).contains("bestPlayer").contains(Player.class.getName()); + public void should_show_information_in_toString() throws Exception { + fieldDescription = new FieldDescription(Player.class.getDeclaredField("name"), PLAYER_TYPE); + assertThat(fieldDescription.toString()).contains("name") + .contains(Player.class.getName()) + .contains(Name.class.getName()); } @Test public void should_detect_real_number_correctly() throws Exception { - fieldDescription = new FieldDescription("double", new TypeDescription(new TypeName(double.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("sizeDouble"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("double").isTrue(); - fieldDescription = new FieldDescription("Double", new TypeDescription(new TypeName(Double.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("sizeAsDoubleWrapper"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("Double").isTrue(); - fieldDescription = new FieldDescription("float", new TypeDescription(new TypeName(float.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("size"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("float").isTrue(); - fieldDescription = new FieldDescription("Float", new TypeDescription(new TypeName(Float.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("sizeAsFloatWrapper"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("Float").isTrue(); + // not real number types - fieldDescription = new FieldDescription("int", new TypeDescription(new TypeName(int.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("pointsPerGame"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("int").isFalse(); - fieldDescription = new FieldDescription("Integer", new TypeDescription(new TypeName(Integer.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("pointsPerGame"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("Integer").isFalse(); - fieldDescription = new FieldDescription("String", new TypeDescription(new TypeName(String.class))); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("team"), PLAYER_TYPE); assertThat(fieldDescription.isRealNumberType()).as("String").isFalse(); } - @Test - public void should_detect_predicate_correctly() throws Exception { - TypeDescription boolDesc = new TypeDescription(new TypeName(boolean.class)); - String[] list = new String[] { "anything", "isSomething", "somethingElse" }; - for (String p : list) { - fieldDescription = new FieldDescription(p, boolDesc); - assertThat(fieldDescription.isPredicate()).as(p + ":bool").isTrue(); - } - TypeDescription floatDesc = new TypeDescription(new TypeName(float.class)); - for (String p : list) { - fieldDescription = new FieldDescription(p, floatDesc); - assertThat(fieldDescription.isPredicate()).as(p + ":float").isFalse(); - } - } - @Test public void should_generate_default_predicate_correctly() throws Exception { - fieldDescription = new FieldDescription("bad", boolDesc); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("bad"), PLAYER_TYPE); assertThat(fieldDescription.getNegativePredicate()).as("negative").isEqualTo("isNotBad"); assertThat(fieldDescription.getPredicate()).as("positive").isEqualTo("isBad"); } @Test - public void should_generate_readable_predicate_for_javadoc() { - fieldDescription = new FieldDescription("bad", boolDesc); + public void should_generate_readable_predicate_for_javadoc() throws Exception { + fieldDescription = new FieldDescription(Player.class.getDeclaredField("bad"), PLAYER_TYPE); assertThat(fieldDescription.getPredicateForJavadoc()).isEqualTo("is bad"); assertThat(fieldDescription.getNegativePredicateForJavadoc()).isEqualTo("is not bad"); } @Test - public void should_generate_readable_predicate_for_error_message() { - fieldDescription = new FieldDescription("bad", boolDesc); + public void should_generate_readable_predicate_for_error_message() throws Exception { + fieldDescription = new FieldDescription(Player.class.getDeclaredField("bad"), PLAYER_TYPE); assertThat(fieldDescription.getPredicateForErrorMessagePart1()).isEqualTo("is bad"); assertThat(fieldDescription.getPredicateForErrorMessagePart2()).isEqualTo("is not"); - fieldDescription = new FieldDescription("canBeGood", boolDesc); - assertThat(fieldDescription.getPredicateForErrorMessagePart1()).isEqualTo("can be good"); - assertThat(fieldDescription.getPredicateForErrorMessagePart2()).isEqualTo("cannot"); + fieldDescription = new FieldDescription(Player.class.getDeclaredField("isDisabled"), PLAYER_TYPE); + assertThat(fieldDescription.getPredicateForErrorMessagePart1()).isEqualTo("is disabled"); + assertThat(fieldDescription.getPredicateForErrorMessagePart2()).isEqualTo("is not"); } } 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 a519d9bd..74800c8f 100644 --- a/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java +++ b/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,130 +12,124 @@ */ package org.assertj.assertions.generator.description; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Collections; -import java.util.List; - +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.data.nba.Player; +import org.junit.BeforeClass; import org.junit.Test; +import java.lang.reflect.Method; + +import static org.assertj.core.api.Assertions.assertThat; + public class GetterDescriptionTest { - private static final TypeDescription PLAYER_TYPE_DESCRIPTION = new TypeDescription(new TypeName(Player.class)); - private static final TypeDescription BOOLEAN_TYPE_DESCRIPTION = new TypeDescription(new TypeName(boolean.class)); - private static final List EMPTY_TYPENAME_LIST = Collections. emptyList();; + private static final TypeToken PLAYER_TYPE_DESCRIPTION = TypeToken.of(Player.class); private GetterDescription getterDescription; - @Test - public void should_create_valid_typename_from_class() { - getterDescription = new GetterDescription("bestPlayer", "getBestPlayer", PLAYER_TYPE_DESCRIPTION, - EMPTY_TYPENAME_LIST); - assertThat(getterDescription.getPropertyName()).isEqualTo("bestPlayer"); - assertThat(getterDescription.getTypeName()).isEqualTo("Player"); - assertThat(getterDescription.getElementTypeName(Player.class.getPackage().getName())).isNull(); + private static Method PLAYER_GET_POINTS_METHOD; + + @BeforeClass + public static void setupClass() throws Exception { + PLAYER_GET_POINTS_METHOD = Player.class.getMethod("getPoints"); } @Test - public void should_show_information_in_toString() { - getterDescription = new GetterDescription("bestPlayer", "getBestPlayer", PLAYER_TYPE_DESCRIPTION, - EMPTY_TYPENAME_LIST); - assertThat(getterDescription.toString()).contains("bestPlayer").contains(Player.class.getName()); + public void should_create_valid_typename_from_class() throws Exception { + getterDescription = new GetterDescription("points", PLAYER_TYPE_DESCRIPTION, PLAYER_GET_POINTS_METHOD); + assertThat(getterDescription.getName()).isEqualTo("points"); + assertThat(getterDescription.getTypeName(false, false)).isEqualTo("List"); + assertThat(getterDescription.getElementTypeName(Player.class.getPackage().getName())).isEqualTo("int[]"); } @Test - public void should_not_be_predicate() { - getterDescription = new GetterDescription("bestPlayer", "getBestPlayer", PLAYER_TYPE_DESCRIPTION, - EMPTY_TYPENAME_LIST); - assertThat(getterDescription.isPredicate()).as("bestPlayer").isFalse(); - getterDescription = new GetterDescription("runFlag", "getRunFlag", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); - assertThat(getterDescription.isPredicate()).as("runFlag").isFalse(); + public void should_show_information_in_toString() throws Exception { + getterDescription = new GetterDescription("points", PLAYER_TYPE_DESCRIPTION, PLAYER_GET_POINTS_METHOD); + assertThat(getterDescription.toString()).contains("points").contains("List"); } @Test - public void should_be_predicate() { - for (String p : new String[] { "is", "can", "was", "has", "should" }) { - getterDescription = new GetterDescription("bestPlayer", p + "BestPlayer", BOOLEAN_TYPE_DESCRIPTION, - EMPTY_TYPENAME_LIST); - assertThat(getterDescription.isPredicate()).as(p).isTrue(); - } + public void should_not_be_predicate() throws Exception { + getterDescription = new GetterDescription("points", PLAYER_TYPE_DESCRIPTION, PLAYER_GET_POINTS_METHOD); + assertThat(getterDescription.isPredicate()).as("points").isFalse(); + getterDescription = new GetterDescription("rookie", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("isRookie")); + assertThat(getterDescription.isPredicate()).as("rookie").isTrue(); } @Test - public void should_generate_predicate_for_javadoc() { - getterDescription = new GetterDescription("rookie", "isRookie", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + public void should_generate_predicate_for_javadoc() throws Exception { + getterDescription = new GetterDescription("rookie", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("isRookie")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("is rookie"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("is not rookie"); - getterDescription = new GetterDescription("", "wasRookie", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("rookie", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("wasRookie")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("was rookie"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("was not rookie"); - getterDescription = new GetterDescription("", "shouldWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("shouldWin")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("should win"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("should not win"); - getterDescription = new GetterDescription("", "canWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("canWin")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("can win"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("cannot win"); - getterDescription = new GetterDescription("", "willWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("willWin")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("will win"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("will not win"); - getterDescription = new GetterDescription("", "hasTrophy", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("trophy", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("hasTrophy")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("has trophy"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("does not have trophy"); - getterDescription = new GetterDescription("", "doesNotHaveFun", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("fun", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("doesNotHaveFun")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("does not have fun"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("has fun"); - getterDescription = new GetterDescription("", "cannotWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("cannotWin")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("cannot win"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("can win"); - getterDescription = new GetterDescription("", "shouldNotPlay", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("play", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("shouldNotPlay")); assertThat(getterDescription.getPredicateForJavadoc()).isEqualTo("should not play"); assertThat(getterDescription.getNegativePredicateForJavadoc()).isEqualTo("should play"); } @Test - public void should_generate_predicate_for_error_message() { - getterDescription = new GetterDescription("rookie", "isRookie", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + public void should_generate_predicate_for_error_message() throws Exception { + getterDescription = new GetterDescription("rookie", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("isRookie")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("is rookie"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("is not"); - getterDescription = new GetterDescription("", "wasRookie", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("rookie", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("wasRookie")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("was rookie"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("was not"); - getterDescription = new GetterDescription("", "shouldWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("shouldWin")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("should win"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("should not"); - getterDescription = new GetterDescription("", "canWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("canWin")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("can win"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("cannot"); - getterDescription = new GetterDescription("", "willWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("willWin")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("will win"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("will not"); - getterDescription = new GetterDescription("", "hasTrophy", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("trophy", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("hasTrophy")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("has trophy"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("does not have"); - getterDescription = new GetterDescription("", "doesNotHaveFun", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("fun", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("doesNotHaveFun")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("does not have fun"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("has"); - getterDescription = new GetterDescription("", "cannotWin", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("win", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("cannotWin")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("cannot win"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("can"); - getterDescription = new GetterDescription("", "shouldNotPlay", BOOLEAN_TYPE_DESCRIPTION, EMPTY_TYPENAME_LIST); + getterDescription = new GetterDescription("play", PLAYER_TYPE_DESCRIPTION, Player.class.getMethod("shouldNotPlay")); assertThat(getterDescription.getPredicateForErrorMessagePart1()).isEqualTo("should not play"); assertThat(getterDescription.getPredicateForErrorMessagePart2()).isEqualTo("should"); } diff --git a/src/test/java/org/assertj/assertions/generator/description/TypeDescriptionTest.java b/src/test/java/org/assertj/assertions/generator/description/TypeDescriptionTest.java deleted file mode 100644 index 6f414fba..00000000 --- a/src/test/java/org/assertj/assertions/generator/description/TypeDescriptionTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * 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-2015 the original author or authors. - */ -package org.assertj.assertions.generator.description; - -import static org.junit.rules.ExpectedException.none; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - - -public class TypeDescriptionTest { - - @Rule - public ExpectedException thrown = none(); - - @SuppressWarnings("unused") - @Test - public void should_throw_exception_in_constructor_call_if_typename_parameter_is_null() throws Exception { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("typeName must not be null."); - new TypeDescription(null); - } - -} diff --git a/src/test/java/org/assertj/assertions/generator/description/TypeNameTest.java b/src/test/java/org/assertj/assertions/generator/description/TypeNameTest.java deleted file mode 100644 index 4f0b4094..00000000 --- a/src/test/java/org/assertj/assertions/generator/description/TypeNameTest.java +++ /dev/null @@ -1,283 +0,0 @@ -/** - * 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-2015 the original author or authors. - */ -package org.assertj.assertions.generator.description; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; - -import org.assertj.assertions.generator.NestedClassesTest; -import org.assertj.assertions.generator.data.OuterClass; -import org.assertj.assertions.generator.data.nba.Player; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; - -@RunWith(Theories.class) -public class TypeNameTest implements NestedClassesTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - private TypeName typeName; - - @Test - public void should_create_valid_typename_from_class() { - typeName = new TypeName(Player.class); - assertThat(typeName.getSimpleName()).isEqualTo("Player"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("Player"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("Player"); - assertThat(typeName.getPackageName()).isEqualTo("org.assertj.assertions.generator.data.nba"); - assertThat(typeName.getFullyQualifiedClassName()).isEqualTo("org.assertj.assertions.generator.data.nba.Player"); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isFalse(); - } - - @Theory - public void should_create_valid_typename_from_nestedclass(NestedClass nestedClass) { - typeName = new TypeName(nestedClass.getNestedClass()); - assertThat(typeName.getSimpleName()).isEqualTo(nestedClass.getNestedClass().getSimpleName()); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo(nestedClass.getClassNameWithOuterClass()); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo(nestedClass.getClassNameWithOuterClassNotSeparatedBytDots()); - assertThat(typeName.getOuterClassTypeName()).isEqualTo(new TypeName( - "org.assertj.assertions.generator.data.OuterClass")); - assertThat(typeName.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); - assertThat(typeName.getFullyQualifiedClassName()).isEqualTo("org.assertj.assertions.generator.data." - + nestedClass.getClassNameWithOuterClass()); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isFalse(); - assertThat(typeName.isNested()).isTrue(); - } - - @Test - public void should_create_valid_typename() { - typeName = new TypeName("Player", "org.assertj.assertions.generator.data"); - assertThat(typeName.getSimpleName()).isEqualTo("Player"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("Player"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("Player"); - assertThat(typeName.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); - assertThat(typeName.getFullyQualifiedClassName()).isEqualTo("org.assertj.assertions.generator.data.Player"); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isFalse(); - } - - @Test - public void should_create_valid_typename_from_type_name_string_description() { - typeName = new TypeName("org.assertj.assertions.generator.data.Player"); - assertThat(typeName.getSimpleName()).isEqualTo("Player"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("Player"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("Player"); - assertThat(typeName.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isFalse(); - assertThat(typeName.isRealNumber()).isFalse(); - assertThat(typeName.isWholeNumber()).isFalse(); - assertThat(typeName.isNested()).isFalse(); - assertThat(typeName.getOuterClassTypeName()).isNull(); - } - - @Test - public void should_create_valid_nested_typename_from_type_name_string_description() { - typeName = new TypeName("org.assertj.assertions.generator.data.Player.Stats"); - assertThat(typeName.getSimpleName()).isEqualTo("Stats"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("Player.Stats"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("PlayerStats"); - assertThat(typeName.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isFalse(); - assertThat(typeName.isRealNumber()).isFalse(); - assertThat(typeName.isWholeNumber()).isFalse(); - assertThat(typeName.isNested()).isTrue(); - assertThat(typeName.getOuterClassTypeName()).isEqualTo(new TypeName("org.assertj.assertions.generator.data.Player")); - } - - @Test - public void should_create_valid_typename_for_primitive() { - typeName = new TypeName(int.class); - assertThat(typeName.getSimpleName()).isEqualTo("int"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("int"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("int"); - assertThat(typeName.getPackageName()).isEmpty(); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isTrue(); - } - - @Test - public void should_create_valid_typename_for_primitive_from_type_name_string_description() { - typeName = new TypeName("int"); - assertThat(typeName.getSimpleName()).isEqualTo("int"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("int"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("int"); - assertThat(typeName.getPackageName()).isEmpty(); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isTrue(); - // same - typeName = new TypeName("int", null); - assertThat(typeName.getSimpleName()).isEqualTo("int"); - assertThat(typeName.getSimpleNameWithOuterClass()).isEqualTo("int"); - assertThat(typeName.getSimpleNameWithOuterClassNotSeparatedByDots()).isEqualTo("int"); - assertThat(typeName.getPackageName()).isEmpty(); - assertThat(typeName.belongsToJavaLangPackage()).isFalse(); - assertThat(typeName.isPrimitive()).isTrue(); - } - - @Test - public void should_fail_if_typename_description_is_empty() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("type name should not be blank or null"); - typeName = new TypeName(""); - } - - @Test - public void should_detect_primitives_typename() { - assertThat(new TypeName(int.class).isPrimitive()).isTrue(); - assertThat(new TypeName(long.class).isPrimitive()).isTrue(); - assertThat(new TypeName(short.class).isPrimitive()).isTrue(); - assertThat(new TypeName(boolean.class).isPrimitive()).isTrue(); - assertThat(new TypeName(char.class).isPrimitive()).isTrue(); - assertThat(new TypeName(byte.class).isPrimitive()).isTrue(); - assertThat(new TypeName(float.class).isPrimitive()).isTrue(); - assertThat(new TypeName(double.class).isPrimitive()).isTrue(); - assertThat(new TypeName(String.class).isPrimitive()).isFalse(); - assertThat(new TypeName("test.Boolean").isPrimitive()).isFalse(); - } - - @Test - public void should_detect_real_numbers_typename() { - assertThat(new TypeName(int.class).isRealNumber()).isFalse(); - assertThat(new TypeName(long.class).isRealNumber()).isFalse(); - assertThat(new TypeName(short.class).isRealNumber()).isFalse(); - assertThat(new TypeName(boolean.class).isRealNumber()).isFalse(); - assertThat(new TypeName(char.class).isRealNumber()).isFalse(); - assertThat(new TypeName(byte.class).isRealNumber()).isFalse(); - assertThat(new TypeName(float.class).isRealNumber()).isTrue(); - assertThat(new TypeName(Float.class).isRealNumber()).isTrue(); - assertThat(new TypeName(double.class).isRealNumber()).isTrue(); - assertThat(new TypeName(Double.class).isRealNumber()).isTrue(); - assertThat(new TypeName(String.class).isRealNumber()).isFalse(); - assertThat(new TypeName("test.Double").isRealNumber()).isFalse(); - } - - @Test - public void should_detect_whole_numbers_typename() { - assertThat(new TypeName(int.class).isWholeNumber()).as("int").isTrue(); - assertThat(new TypeName(Integer.class).isWholeNumber()).as("Integer").isTrue(); - assertThat(new TypeName(long.class).isWholeNumber()).as("long").isTrue(); - assertThat(new TypeName(Long.class).isWholeNumber()).as("Long").isTrue(); - assertThat(new TypeName(short.class).isWholeNumber()).as("short").isTrue(); - assertThat(new TypeName(Short.class).isWholeNumber()).as("Short").isTrue(); - assertThat(new TypeName(byte.class).isWholeNumber()).as("byte").isTrue(); - assertThat(new TypeName(Byte.class).isWholeNumber()).as("Byte").isTrue(); - assertThat(new TypeName(boolean.class).isWholeNumber()).isFalse(); - assertThat(new TypeName(char.class).isWholeNumber()).isFalse(); - assertThat(new TypeName(float.class).isWholeNumber()).isFalse(); - assertThat(new TypeName(Float.class).isWholeNumber()).isFalse(); - assertThat(new TypeName(double.class).isWholeNumber()).isFalse(); - assertThat(new TypeName(Double.class).isWholeNumber()).isFalse(); - assertThat(new TypeName(String.class).isWholeNumber()).isFalse(); - assertThat(new TypeName("test.Integer").isWholeNumber()).isFalse(); - } - - @Test - public void should_detect_boolean_typename() { - assertThat(new TypeName(boolean.class).isBoolean()).isTrue(); - assertThat(new TypeName(Boolean.class).isBoolean()).isTrue(); - assertThat(new TypeName("boolean").isBoolean()).isTrue(); - assertThat(new TypeName("Boolean").isBoolean()).isFalse(); - assertThat(new TypeName(char.class).isBoolean()).isFalse(); - } - - @Test - public void should_detect_character_typename() { - assertThat(new TypeName(char.class).isChar()).isTrue(); - assertThat(new TypeName(Character.class).isChar()).isTrue(); - assertThat(new TypeName("char").isChar()).isTrue(); - assertThat(new TypeName("Character").isChar()).isFalse(); - assertThat(new TypeName(int.class).isChar()).isFalse(); - } - - @Test - public void should_detect_primitive_wrapper_typename() { - assertThat(new TypeName(Integer.class).isPrimitiveWrapper()).as("Integer").isTrue(); - assertThat(new TypeName(Long.class).isPrimitiveWrapper()).as("Long").isTrue(); - assertThat(new TypeName(Short.class).isPrimitiveWrapper()).as("Short").isTrue(); - assertThat(new TypeName(Byte.class).isPrimitiveWrapper()).as("Byte").isTrue(); - assertThat(new TypeName(Boolean.class).isPrimitiveWrapper()).isTrue(); - assertThat(new TypeName(Character.class).isPrimitiveWrapper()).isTrue(); - assertThat(new TypeName(Float.class).isPrimitiveWrapper()).isTrue(); - assertThat(new TypeName(Double.class).isPrimitiveWrapper()).isTrue(); - assertThat(new TypeName(int.class).isPrimitiveWrapper()).as("int").isFalse(); - assertThat(new TypeName(long.class).isPrimitiveWrapper()).as("long").isFalse(); - assertThat(new TypeName(short.class).isPrimitiveWrapper()).as("short").isFalse(); - assertThat(new TypeName(byte.class).isPrimitiveWrapper()).as("byte").isFalse(); - assertThat(new TypeName(boolean.class).isPrimitiveWrapper()).isFalse(); - assertThat(new TypeName(char.class).isPrimitiveWrapper()).isFalse(); - assertThat(new TypeName(float.class).isPrimitiveWrapper()).isFalse(); - assertThat(new TypeName(double.class).isPrimitiveWrapper()).isFalse(); - assertThat(new TypeName(String.class).isPrimitiveWrapper()).isFalse(); - assertThat(new TypeName("test.Integer").isPrimitiveWrapper()).isFalse(); - } - - @Test - public void should_detect_array_typename() { - assertThat(new TypeName(String[].class).isArray()).isTrue(); - assertThat(new TypeName(int[].class).isArray()).isTrue(); - assertThat(new TypeName(int.class).isArray()).isFalse(); - assertThat(new TypeName(String.class).isArray()).isFalse(); - } - - @Test - public void should_detect_nested_typename() { - assertThat(new TypeName(String.class).isNested()).isFalse(); - assertThat(new TypeName(OuterClass.class).isNested()).isFalse(); - assertThat(new TypeName(OuterClass.InnerPerson.class).isNested()).isTrue(); - assertThat(new TypeName(OuterClass.InnerPerson.IP_InnerPerson.class).isNested()).isTrue(); - assertThat(new TypeName(OuterClass.StaticNestedPerson.class).isNested()).isTrue(); - assertThat(new TypeName(OuterClass.StaticNestedPerson.SNP_InnerPerson.class).isNested()).isTrue(); - assertThat(new TypeName(OuterClass.StaticNestedPerson.SNP_StaticNestedPerson.class).isNested()).isTrue(); - } - - @Test - public void should_fail_if_type_simple_name_is_null() { - try { - typeName = new TypeName(null, "org.assertj.assertions.generator.data"); - failBecauseExceptionWasNotThrown(IllegalArgumentException.class); - } catch (IllegalArgumentException iae) { - assertThat(iae).hasMessage("type simple name should not be null"); - } - } - - @Test - public void compare_to_should_compare_classes_fully_qualified_names() { - // compare package before all - TypeName typeNameData1A = new TypeName("A", "org.assertj.assertions.generator.data1"); - TypeName typeNameData2B = new TypeName("A", "org.assertj.assertions.generator.data2"); - assertThat(typeNameData1A.compareTo(typeNameData1A)).isZero(); - assertThat(typeNameData1A.compareTo(typeNameData2B)).isNegative(); - assertThat(typeNameData2B.compareTo(typeNameData1A)).isPositive(); - // if package are equals, compare class simple name - TypeName typeNameA = new TypeName("A", "org.assertj.assertions.generator.data"); - TypeName typeNameB = new TypeName("B", "org.assertj.assertions.generator.data"); - assertThat(typeNameA.compareTo(typeNameA)).isZero(); - assertThat(typeNameA.compareTo(typeNameB)).isNegative(); - assertThat(typeNameB.compareTo(typeNameA)).isPositive(); - } - - @Test - public void should_show_information_in_toString() { - assertThat(new TypeName("A", "org.mypackage").toString()).isEqualTo("org.mypackage.A"); - assertThat(new TypeName(int.class).toString()).isEqualTo("int"); - } - -} 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 a8edc4dd..70f77dac 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 @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,12 +12,7 @@ */ package org.assertj.assertions.generator.description.converter; -import static org.assertj.core.api.Assertions.assertThat; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.BeanWithExceptionsTest; import org.assertj.assertions.generator.NestedClassesTest; import org.assertj.assertions.generator.data.ArtWork; @@ -29,224 +24,283 @@ import org.assertj.assertions.generator.data.nba.PlayerAgent; import org.assertj.assertions.generator.description.ClassDescription; import org.assertj.assertions.generator.description.GetterDescription; +import org.assertj.assertions.generator.util.TypeUtil; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + @RunWith(Theories.class) public class ClassToClassDescriptionConverterTest implements NestedClassesTest, BeanWithExceptionsTest { - private static ClassToClassDescriptionConverter converter; - - @BeforeClass - public static void beforeAllTests() { - converter = new ClassToClassDescriptionConverter(); - } - - @Test - public void should_build_player_class_description() throws Exception { - ClassDescription classDescription = converter.convertToClassDescription(Player.class); - assertThat(classDescription.getClassName()).isEqualTo("Player"); - assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo("Player"); - assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data.nba"); - assertThat(classDescription.getGettersDescriptions()).hasSize(11); - } - - @Test - public void should_build_movie_class_description() throws Exception { - ClassDescription classDescription = converter.convertToClassDescription(Movie.class); - assertThat(classDescription.getClassName()).isEqualTo("Movie"); - assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo("Movie"); - assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); - assertThat(classDescription.getGettersDescriptions()).hasSize(3); - assertThat(classDescription.getFieldsDescriptions()).hasSize(4); - assertThat(classDescription.getDeclaredGettersDescriptions()).hasSize(2); - assertThat(classDescription.getDeclaredFieldsDescriptions()).hasSize(3); - assertThat(classDescription.getSuperType()).isEqualTo(ArtWork.class); - } - - @Theory - public void should_build_nestedclass_description(NestedClass nestedClass) throws Exception { - Class clazz = nestedClass.getNestedClass(); - ClassDescription classDescription = converter.convertToClassDescription(clazz); - assertThat(classDescription.getClassName()).isEqualTo(clazz.getSimpleName()); - assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo(nestedClass.getClassNameWithOuterClass()); - assertThat(classDescription.getPackageName()).isEqualTo(clazz.getPackage().getName()); - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - } - - @Theory - public void should_build_getter_with_exception_description(GetterWithException getter) throws Exception { - Class clazz = getter.getBeanClass(); - ClassDescription classDescription = converter.convertToClassDescription(clazz); - assertThat(classDescription.getClassName()).isEqualTo(clazz.getSimpleName()); - assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo(clazz.getSimpleName()); - assertThat(classDescription.getPackageName()).isEqualTo(clazz.getPackage().getName()); - assertThat(classDescription.getGettersDescriptions()).hasSize(4); - - for (GetterDescription desc : classDescription.getGettersDescriptions()) { - if (desc.getPropertyName().equals(getter.getPropertyName())) { - assertThat(desc.getExceptions()).containsOnly(getter.getExceptions()); - break; - } - } - } - - @Test - public void should_build_class_description_for_iterable_of_primitive_type_array() throws Exception { - class Type { - List scores; - - @SuppressWarnings("unused") - public List getScores() { - return scores; - } - } - ClassDescription classDescription = converter.convertToClassDescription(Type.class); - assertThat(classDescription.getClassName()).isEqualTo("Type"); - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); - assertThat(getterDescription.isIterableType()).as("getterDescription must be iterable").isTrue(); - assertThat(getterDescription.getElementTypeName(Type.class.getPackage().getName())).isEqualTo("int[]"); - assertThat(getterDescription.isArrayType()).as("getterDescription must not be an array").isFalse(); - } - - @Test - public void should_build_class_description_for_array_of_primitive_type_array() throws Exception { - class Type { - int[][] scores; - - @SuppressWarnings("unused") - public int[][] getScores() { - return scores; - } - } - ClassDescription classDescription = converter.convertToClassDescription(Type.class); - assertThat(classDescription.getClassName()).isEqualTo("Type"); - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); - assertThat(getterDescription.isIterableType()).as("getterDescription is an iterable ?").isFalse(); - assertThat(getterDescription.isArrayType()).as("getterDescription is an array ?").isTrue(); - assertThat(getterDescription.getElementTypeName(Type.class.getPackage().getName())).isEqualTo("int[]"); - } - - @Test - public void should_build_class_description_for_enum_type() throws Exception { - ClassDescription classDescription = converter.convertToClassDescription(TreeEnum.class); - assertThat(classDescription.getClassName()).isEqualTo("TreeEnum"); - // should not contain getDeclaringClassGetter as we don't want to have hasDeclaringClass assertion - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); - assertThat(getterDescription.isIterableType()).as("getterDescription must be iterable").isTrue(); - assertThat(getterDescription.getElementTypeName(TreeEnum.class.getPackage().getName())).isEqualTo("TreeEnum"); - assertThat(getterDescription.isArrayType()).as("getterDescription must be an array").isFalse(); - } - - @Test - public void should_build_class_description_for_iterable_of_Object_type() throws Exception { - // Given - class Type { - List players; - - @SuppressWarnings("unused") - public List getPlayers() { - return players; - } - } - - // When - ClassDescription classDescription = converter.convertToClassDescription(Type.class); - - // Then - assertThat(classDescription.getClassName()).isEqualTo("Type"); - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); - assertThat(getterDescription.isIterableType()).as("getterDescription must be iterable").isTrue(); - assertThat(getterDescription.getElementTypeName(Type.class.getPackage().getName())).isEqualTo("org.assertj.assertions.generator.data.nba.Player[]"); - assertThat(getterDescription.isArrayType()).as("getterDescription is not an array").isFalse(); - } - - @Test - public void should_build_class_description_for_interface() throws Exception { - // Given an interface - // When - ClassDescription classDescription = converter.convertToClassDescription(PlayerAgent.class); - - // Then - assertThat(classDescription.getClassName()).isEqualTo("PlayerAgent"); - assertThat(classDescription.getSuperType()).isNull(); - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); - assertThat(getterDescription.isIterableType()).as("getterDescription is not iterable").isFalse(); - assertThat(getterDescription.getPropertyName()).isEqualTo("managedPlayer"); - assertThat(getterDescription.getTypeName()).isEqualTo("Player"); - } - - @Test - public void should_build_fellowshipOfTheRing_class_description() throws Exception { - ClassDescription classDescription = converter.convertToClassDescription(FellowshipOfTheRing.class); - assertThat(classDescription.getClassName()).isEqualTo("FellowshipOfTheRing"); - assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo("FellowshipOfTheRing"); - assertThat(classDescription.getClassNameWithOuterClassNotSeparatedByDots()).isEqualTo("FellowshipOfTheRing"); - assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data.lotr"); - assertThat(classDescription.getGettersDescriptions()).hasSize(1); - } - - @Test - public void should_handle_toString() { - ClassDescription classDescription = converter.convertToClassDescription(FellowshipOfTheRing.class); - assertThat(classDescription.toString()).contains(FellowshipOfTheRing.class.getName()); - } - - @Test - public void should_build_class_description_for_class_with_public_fields() throws Exception { - ClassDescription classDescription = converter.convertToClassDescription(Team.class); - assertThat(classDescription.getClassName()).isEqualTo("Team"); - assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo("Team"); - assertThat(classDescription.getClassNameWithOuterClassNotSeparatedByDots()).isEqualTo("Team"); - assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); - assertThat(classDescription.getGettersDescriptions()).extracting("propertyName").containsExactly("division"); - assertThat(classDescription.getFieldsDescriptions()).extracting("name").containsOnly("name", - "oldNames", - "westCoast", - "rank", - "players", - "points", - "victoryRatio"); - } - - @Test - public void bug21_reflection_error_on_iterable_ParameterizedType() { - class MySQLException extends SQLException { - private static final long serialVersionUID = 1L; - - @SuppressWarnings("unused") - public SQLException getExceptionChain() { - return null; - } - } - ClassDescription classDescription = converter.convertToClassDescription(MySQLException.class); - // exceptionChain is a SQLException which is an Iterable but looking only at SQLException we can't deduce - // iterable type - assertThat(classDescription.getGettersDescriptions()).extracting("propertyName").contains("exceptionChain"); - } - - @Test - public void should_only_describe_overriden_getter_once() { - ClassDescription myClassDescription = converter.convertToClassDescription(ClassOverridingGetter.class); - assertThat(myClassDescription.getGettersDescriptions()).extracting("propertyName").containsOnlyOnce("myList"); - } - - public interface InterfaceWithGetter { - public abstract List getMyList(); - } - - class ClassOverridingGetter implements InterfaceWithGetter { - @Override - public ArrayList getMyList() { - return null; - } - } + private static ClassToClassDescriptionConverter converter; + + @BeforeClass + public static void beforeAllTests() { + converter = new ClassToClassDescriptionConverter(); + } + + @Test + public void should_build_player_class_description() throws Exception { + // Given + Class clazz = Player.class; + + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo(clazz.getSimpleName()); + assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data.nba"); + + assertThat(classDescription.getGettersDescriptions()).hasSize(19); + } + + @Test + public void should_build_movie_class_description() throws Exception { + // Given + Class clazz = Movie.class; + + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo(clazz.getSimpleName()); + assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); + + assertThat(classDescription.getGettersDescriptions()).hasSize(3); + assertThat(classDescription.getFieldsDescriptions()).hasSize(4); + assertThat(classDescription.getDeclaredGettersDescriptions()).hasSize(2); + assertThat(classDescription.getDeclaredFieldsDescriptions()).hasSize(3); + assertThat(classDescription.getSuperType()).isEqualTo(TypeToken.of(ArtWork.class)); + } + + @Theory + public void should_build_nestedclass_description(NestedClass nestedClass) throws Exception { + Class clazz = nestedClass.getNestedClass(); + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo(nestedClass.getClassNameWithOuterClass()); + assertThat(classDescription.getPackageName()).isEqualTo(clazz.getPackage().getName()); + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + } + + @Theory + public void should_build_getter_with_exception_description(GetterWithException getter) throws Exception { + TypeToken type = getter.getBeanClass(); + Class clazz = type.getRawType(); + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo(clazz.getSimpleName()); + assertThat(classDescription.getPackageName()).isEqualTo(clazz.getPackage().getName()); + assertThat(classDescription.getGettersDescriptions()).hasSize(4); + + for (GetterDescription desc : classDescription.getGettersDescriptions()) { + if (desc.getName().equals(getter.getPropertyName())) { + assertThat(desc.getExceptions()).containsOnly(getter.getExceptions().toArray(new TypeToken[]{})); + break; + } + } + } + + class WithPrimitiveArrayCollection { + List scores; + + @SuppressWarnings("unused") + public List getScores() { + return scores; + } + } + + @Test + public void should_build_class_description_for_iterable_of_primitive_type_array() throws Exception { + // Given + Class clazz = WithPrimitiveArrayCollection.class; + + // When + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + + // Then + GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); + assertThat(getterDescription.isIterableType()) + .as("getterDescription must be iterable") + .isTrue(); + assertThat(getterDescription.getElementTypeName(clazz.getPackage().getName())) + .as("getterDesc must have correct element type") + .isEqualTo("int[]"); + assertThat(getterDescription.isArrayType()) + .as("getterDescription must not be an array") + .isFalse(); + } + + static class WithPrimitiveArrayArrayCollection { + int[][] scores; + + @SuppressWarnings("unused") + public int[][] getScores() { + return scores; + } + } + + @Test(expected = IllegalArgumentException.class) + public void should_fail_to_build_class_description_for_local_class() throws Exception { + class Local {} + converter.convertToClassDescription(Local.class); + } + + @Test + public void should_build_class_description_for_array_of_primitive_type_array() throws Exception { + ClassDescription classDescription = converter.convertToClassDescription(WithPrimitiveArrayArrayCollection.class); + assertThat(classDescription.getClassName()).isEqualTo(WithPrimitiveArrayArrayCollection.class.getName()); + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); + assertThat(getterDescription.isIterableType()).as("getterDescription is an iterable ?").isFalse(); + assertThat(getterDescription.isArrayType()).as("getterDescription is an array ?").isTrue(); + assertThat(getterDescription.getElementTypeName(WithPrimitiveArrayArrayCollection.class.getPackage().getName())).isEqualTo("int[]"); + } + + @Test + public void should_build_class_description_for_enum_type() throws Exception { + ClassDescription classDescription = converter.convertToClassDescription(TreeEnum.class); + assertThat(classDescription.getClassName()).isEqualTo(TreeEnum.class.getName()); + // should not contain getDeclaringClassGetter as we don't want to have hasDeclaringClass assertion + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); + assertThat(getterDescription.isIterableType()).as("getterDescription must be iterable").isTrue(); + assertThat(getterDescription.getElementTypeName(TreeEnum.class.getPackage().getName())) + .as("getterDescription must get the internal component type without package") + .isEqualTo(TreeEnum.class.getSimpleName()); + assertThat(getterDescription.isArrayType()).as("getterDescription must be an array").isFalse(); + } + + class WithIterableObjectType { + List players; + + @SuppressWarnings("unused") + public List getPlayers() { + return players; + } + } + + @Test + public void should_build_class_description_for_iterable_of_Object_type() throws Exception { + // Given + Class clazz = WithIterableObjectType.class; + + // When + ClassDescription classDescription = converter.convertToClassDescription(clazz); + + // Then + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); + assertThat(getterDescription.isIterableType()) + .as("getterDescription must be iterable") + .isTrue(); + assertThat(getterDescription.getElementTypeName(WithIterableObjectType.class.getPackage().getName())) + .as("getterDesc element type must return correct array type") + .isEqualTo(TypeUtil.getTypeDeclaration(new TypeToken() {}, false, false)); + assertThat(getterDescription.isArrayType()).as("getterDescription is not an array").isFalse(); + } + + @Test + public void should_build_class_description_for_interface() throws Exception { + // Given an interface + Class clazz = PlayerAgent.class; + // When + ClassDescription classDescription = converter.convertToClassDescription(clazz); + + // Then + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getSuperType()).isNull(); + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + GetterDescription getterDescription = classDescription.getGettersDescriptions().iterator().next(); + assertThat(getterDescription.isIterableType()) + .as("getterDescription is not iterable").isFalse(); + assertThat(getterDescription.getName()) + .as("getterDesc must have correct name").isEqualTo("managedPlayer"); + assertThat(getterDescription.getTypeName(false, false)) + .as("getterDesc must have correct owning type").isEqualTo(Player.class.getSimpleName()); + assertThat(getterDescription.getTypeName(true, false)) + .as("getterDesc must have correct owning type").isEqualTo(Player.class.getName()); + } + + @Test + public void should_build_fellowshipOfTheRing_class_description() throws Exception { + // Given + Class clazz = FellowshipOfTheRing.class; + + // Then + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo("FellowshipOfTheRing"); + assertThat(classDescription.getClassNameWithOuterClassNotSeparatedByDots()).isEqualTo("FellowshipOfTheRing"); + assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data.lotr"); + assertThat(classDescription.getGettersDescriptions()).hasSize(1); + } + + @Test + public void should_handle_toString() { + ClassDescription classDescription = converter.convertToClassDescription(FellowshipOfTheRing.class); + assertThat(classDescription.toString()).contains(FellowshipOfTheRing.class.getName()); + } + + @Test + public void should_build_class_description_for_class_with_public_fields() throws Exception { + // Given + Class clazz = Team.class; + + // Then + ClassDescription classDescription = converter.convertToClassDescription(clazz); + assertThat(classDescription.getClassName()).isEqualTo(clazz.getName()); + assertThat(classDescription.getClassNameWithOuterClass()).isEqualTo("Team"); + assertThat(classDescription.getClassNameWithOuterClassNotSeparatedByDots()).isEqualTo("Team"); + assertThat(classDescription.getPackageName()).isEqualTo("org.assertj.assertions.generator.data"); + assertThat(classDescription.getGettersDescriptions()).extracting("name").containsExactly("division"); + assertThat(classDescription.getFieldsDescriptions()).extracting("name").containsOnly("name", + "oldNames", + "westCoast", + "rank", + "players", + "points", + "victoryRatio"); + } + + class Bug21_SQLException extends SQLException { + private static final long serialVersionUID = 1L; + + @SuppressWarnings("unused") + public SQLException getExceptionChain() { + return null; + } + } + + @Test + public void bug21_reflection_error_on_iterable_ParameterizedType() { + ClassDescription classDescription = converter.convertToClassDescription(Bug21_SQLException.class); + // exceptionChain is a SQLException which is an Iterable but looking only at SQLException we can't deduce + // iterable valueType + assertThat(classDescription.getGettersDescriptions()).extracting("name").contains("exceptionChain"); + } + + @Test + public void should_only_describe_overriden_getter_once() { + ClassDescription myClassDescription = converter.convertToClassDescription(ClassOverridingGetter.class); + assertThat(myClassDescription.getGettersDescriptions()).extracting("name").containsOnlyOnce("myList"); + } + + public interface InterfaceWithGetter { + public abstract List getMyList(); + } + + class ClassOverridingGetter implements InterfaceWithGetter { + @Override + public ArrayList getMyList() { + return null; + } + } } 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 cfb8466c..26fe11cd 100644 --- a/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java +++ b/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java @@ -12,40 +12,11 @@ */ package org.assertj.assertions.generator.util; -import static org.assertj.assertions.generator.util.ClassUtil.collectClasses; -import static org.assertj.assertions.generator.util.ClassUtil.declaredGetterMethodsOf; -import static org.assertj.assertions.generator.util.ClassUtil.getClassesRelatedTo; -import static org.assertj.assertions.generator.util.ClassUtil.getNegativePredicateFor; -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.getSimpleNameWithOuterClassNotSeparatedByDots; -import static org.assertj.assertions.generator.util.ClassUtil.getterMethodsOf; -import static org.assertj.assertions.generator.util.ClassUtil.inheritsCollectionOrIsIterable; -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.isValidGetterName; -import static org.assertj.assertions.generator.util.ClassUtil.propertyNameOf; -import static org.assertj.core.api.Assertions.assertThat; - -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.NestedClassesTest; -import org.assertj.assertions.generator.data.ArtWork; -import org.assertj.assertions.generator.data.BeanWithOneException; -import org.assertj.assertions.generator.data.BeanWithTwoExceptions; -import org.assertj.assertions.generator.data.Dollar$; -import org.assertj.assertions.generator.data.Movie; -import org.assertj.assertions.generator.data.Name; -import org.assertj.assertions.generator.data.OuterClass; -import org.assertj.assertions.generator.data.OuterClass.StaticNestedPerson; -import org.assertj.assertions.generator.data.Primitives; -import org.assertj.assertions.generator.data.Team; -import org.assertj.assertions.generator.data.TreeEnum; +import org.assertj.assertions.generator.data.*; import org.assertj.assertions.generator.data.lotr.FellowshipOfTheRing; import org.assertj.assertions.generator.data.lotr.Race; import org.assertj.assertions.generator.data.lotr.Ring; @@ -57,14 +28,23 @@ import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.*; + +import static org.assertj.assertions.generator.util.ClassUtil.*; +import static org.assertj.core.api.Assertions.assertThat; + @RunWith(Theories.class) public class ClassUtilTest implements NestedClassesTest { private static final Class[] NO_PARAMS = new Class[0]; + private static final TypeToken PLAYER_TYPE = TypeToken.of(Player.class); + @Test public void should_get_class_only() { - assertThat(collectClasses(getClass().getClassLoader(), Movie.class.getName())).containsOnly(Movie.class); + assertThat(collectClasses(getClass().getClassLoader(), Movie.class.getName())).containsOnly(TypeToken.of(Movie.class)); } @Test(expected = IllegalArgumentException.class) @@ -72,30 +52,43 @@ public void should_thow_exception_when_classLoader_null() { collectClasses((ClassLoader) null, "org.assertj.assertions.generator.data"); } + // Could easily be a method reference in Java 8 for TypeToken::of + private static final Function, TypeToken> TYPE_TOKEN_TRANSFORM = new Function, TypeToken>() { + @Override + public TypeToken apply(final Class input) { + return TypeToken.of(input); + } + }; + @Test public void should_get_classes_in_package_and_subpackages() { - Set> classesInPackage = collectClasses("org.assertj.assertions.generator.data"); - assertThat(classesInPackage).contains(Player.class, PlayerAgent.class, ArtWork.class, Name.class, Movie.class, - Movie.PublicCategory.class, Ring.class, Race.class, - FellowshipOfTheRing.class, TolkienCharacter.class, - Team.class, - Dollar$.class, - org.assertj.assertions.generator.data.nba.Team.class, - TreeEnum.class, - OuterClass.InnerPerson.IP_InnerPerson.class, - OuterClass.InnerPerson.class, - OuterClass.class, - StaticNestedPerson.SNP_InnerPerson.class, - StaticNestedPerson.class, - StaticNestedPerson.SNP_StaticNestedPerson.class, - BeanWithOneException.class, BeanWithTwoExceptions.class); + Set> classesInPackage = collectClasses("org.assertj.assertions.generator.data"); + List> classes = Arrays.asList(Player.class, PlayerAgent.class, ArtWork.class, Name.class, Movie.class, + Movie.PublicCategory.class, Ring.class, Race.class, + FellowshipOfTheRing.class, TolkienCharacter.class, + Team.class, + Dollar$.class, + org.assertj.assertions.generator.data.nba.Team.class, + TreeEnum.class, + OuterClass.InnerPerson.IP_InnerPerson.class, + OuterClass.InnerPerson.class, + OuterClass.class, + OuterClass.StaticNestedPerson.SNP_InnerPerson.class, + OuterClass.StaticNestedPerson.class, + OuterClass.StaticNestedPerson.SNP_StaticNestedPerson.class, + BeanWithOneException.class, BeanWithTwoExceptions.class); + + // Java 8? :( + assertThat(classesInPackage).containsAll(Lists.transform(classes, TYPE_TOKEN_TRANSFORM)); } @Test public void should_get_classes_with_provided_class_loader() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Set> classesInPackage = collectClasses(classLoader, "org.assertj.assertions.generator.data"); - assertThat(classesInPackage).contains(Player.class, ArtWork.class, Name.class, Movie.class, Ring.class, Race.class); + Set> classesInPackage = collectClasses(classLoader, "org.assertj.assertions.generator.data"); + List> classes = Arrays.asList(Player.class, ArtWork.class, Name.class, Movie.class, Ring.class, Race.class); + + assertThat(classesInPackage).containsAll(Lists.transform(classes, TYPE_TOKEN_TRANSFORM)); } @Test @@ -186,21 +179,21 @@ public void should_return_false_if_string_does_not_follow_getter_name_pattern() @Test public void should_return_getters_methods_only() throws Exception { - Set playerGetterMethods = getterMethodsOf(Player.class, Collections.>emptySet()); + Set playerGetterMethods = getterMethodsOf(PLAYER_TYPE, Collections.>emptySet()); assertThat(playerGetterMethods).contains(Player.class.getMethod("getTeam", NO_PARAMS)) .doesNotContain(Player.class.getMethod("isInTeam", String.class)); } @Test public void should_also_return_inherited_getters_methods() throws Exception { - Set playerGetterMethods = getterMethodsOf(Movie.class, Collections.>emptySet()); + Set playerGetterMethods = getterMethodsOf(TypeToken.of(Movie.class), Collections.>emptySet()); assertThat(playerGetterMethods).contains(Movie.class.getMethod("getReleaseDate", NO_PARAMS), ArtWork.class.getMethod("getTitle", NO_PARAMS)); } @Test public void should_not_return_inherited_getters_methods() throws Exception { - Set playerGetterMethods = declaredGetterMethodsOf(Movie.class, Collections.>emptySet()); + Set playerGetterMethods = declaredGetterMethodsOf(TypeToken.of(Movie.class), Collections.>emptySet()); assertThat(playerGetterMethods).contains(Movie.class.getMethod("getReleaseDate", NO_PARAMS)) .doesNotContain(ArtWork.class.getMethod("getTitle", NO_PARAMS)); } diff --git a/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java b/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java new file mode 100644 index 00000000..35e44315 --- /dev/null +++ b/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java @@ -0,0 +1,100 @@ +/* + * 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-2015 the original author or authors. + */ +package org.assertj.assertions.generator.util; + +import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.AssertionGeneratorTest; +import org.assertj.assertions.generator.description.GetterDescriptionTest; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.List; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +/** + * Describes tests for the {@link TypeUtil} class + */ +public class TypeUtilTest { + @Test + public void isInnerPackageOf() throws Exception { + + assertThat(TypeUtil.isInnerPackageOf(TypeUtilTest.class.getPackage(), + AssertionGeneratorTest.class.getPackage())) + .as("from 'super' package") + .isTrue(); + + assertThat(TypeUtil.isInnerPackageOf(TypeUtilTest.class.getPackage(), + TypeUtilTest.class.getPackage())) + .as("same package") + .isTrue(); + + assertThat(TypeUtil.isInnerPackageOf(TypeUtilTest.class.getPackage(), + GetterDescriptionTest.class.getPackage())) + .as("sibling package") + .isFalse(); + + } + + @SuppressWarnings("unused") + static class Foo { + List listOfT; + List> listOfFooString; + List[]> listOfFooIntArr; + List[]> listOfFooIntArrArrArr; + } + + @Test + public void create_generic_type_declaration() throws Exception { + TypeToken> fooInteger = new TypeToken>(getClass()) {}; + String result = TypeUtil.getTypeDeclaration(fooInteger, false, true); + String expected = String.format("%s.%s.%s", TypeUtilTest.class.getPackage().getName(), TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // nested! + TypeToken>> fooFooInteger = new TypeToken>>(getClass()){}; + result = TypeUtil.getTypeDeclaration(fooFooInteger, false, false); + expected = String.format("%s.%s<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName(), + TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // check getting the field's type + Field listOfTField = Foo.class.getDeclaredField("listOfT"); + result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfTField.getGenericType()), false, false); + expected = String.format("List<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // List of non-T type + Field listOfFooStringField = Foo.class.getDeclaredField("listOfFooString"); + result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfFooStringField.getGenericType()), false, false); + expected = String.format("List<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // List of Foo[] + + Field listOfFooIntArr = Foo.class.getDeclaredField("listOfFooIntArr"); + result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfFooIntArr.getGenericType()), false, false); + expected = String.format("List<%s.%s[]>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // List of Foo[] + Field listOfFooIntArrArrArr = Foo.class.getDeclaredField("listOfFooIntArrArrArr"); + result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfFooIntArrArrArr.getGenericType()), false, false); + expected = String.format("List<%s.%s[]>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + } + + + + +} \ No newline at end of file diff --git a/src/test/resources/AbstractArtWorkAssert.expected.txt b/src/test/resources/AbstractArtWorkAssert.expected.txt index 19cd6893..fb69845a 100644 --- a/src/test/resources/AbstractArtWorkAssert.expected.txt +++ b/src/test/resources/AbstractArtWorkAssert.expected.txt @@ -29,7 +29,7 @@ public abstract class AbstractArtWorkAssert, A // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting publicCategory of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check Movie.PublicCategory actualPublicCategory = actual.getPublicCategory(); if (!Objects.areEqual(actualPublicCategory, publicCategory)) { @@ -52,7 +52,7 @@ public abstract class AbstractMovieAssert, A // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting releaseDate of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check java.util.Date actualReleaseDate = actual.getReleaseDate(); if (!Objects.areEqual(actualReleaseDate, releaseDate)) { @@ -75,7 +75,7 @@ public abstract class AbstractMovieAssert, A // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting producer of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualProducer = actual.producer; if (!Objects.areEqual(actualProducer, producer)) { @@ -99,7 +99,7 @@ public abstract class AbstractMovieAssert, A // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting rating of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - // check + // check value for rating double actualRating = actual.rating; if (actualRating != rating) { failWithMessage(assertjErrorMessage, actual, rating, actualRating); @@ -123,11 +123,11 @@ public abstract class AbstractMovieAssert, A isNotNull(); double actualRating = actual.rating; - + // overrides the default error message with a more explicit one String assertjErrorMessage = String.format("\nExpecting rating:\n <%s>\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualRating, rating, offset, Math.abs(rating - actualRating)); - + // check Assertions.assertThat(actualRating).overridingErrorMessage(assertjErrorMessage).isCloseTo(rating, Assertions.within(offset)); @@ -144,11 +144,11 @@ public abstract class AbstractMovieAssert, A // check that actual Movie we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is true if (!actual.xrated) { failWithMessage("\nExpecting that actual Movie is xrated but is not."); } - + // return the current assertion for method chaining return myself; } @@ -162,11 +162,11 @@ public abstract class AbstractMovieAssert, A // check that actual Movie we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is false if (actual.xrated) { failWithMessage("\nExpecting that actual Movie is not xrated but is."); } - + // return the current assertion for method chaining return myself; } diff --git a/src/test/resources/AnnotatedClassAssert.expected.txt b/src/test/resources/AnnotatedClassAssert.expected.txt index 900bd9df..badd901b 100644 --- a/src/test/resources/AnnotatedClassAssert.expected.txt +++ b/src/test/resources/AnnotatedClassAssert.expected.txt @@ -40,7 +40,7 @@ public class AnnotatedClassAssert extends AbstractObjectAssert 0) { failWithMessage(assertjErrorMessage, actual, java.util.Arrays.toString(actual.getArrayPropertyThrowsException())); } - + + // return the current assertion for method chaining + return this; + } + + + /** + * Verifies that the actual BeanWithOneException is boolean property throws exception. + * @return this assertion object. + * @throws AssertionError - if the actual BeanWithOneException is not boolean property throws exception. + * @throws java.io.IOException if actual.isBooleanPropertyThrowsException() throws one. + */ + public BeanWithOneExceptionAssert isBooleanPropertyThrowsException() throws java.io.IOException { + // check that actual BeanWithOneException we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.isBooleanPropertyThrowsException()) { + failWithMessage("\nExpecting that actual BeanWithOneException is boolean property throws exception but is not."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual BeanWithOneException is not boolean property throws exception. + * @return this assertion object. + * @throws AssertionError - if the actual BeanWithOneException is boolean property throws exception. + * @throws java.io.IOException if actual.isBooleanPropertyThrowsException() throws one. + */ + public BeanWithOneExceptionAssert isNotBooleanPropertyThrowsException() throws java.io.IOException { + // check that actual BeanWithOneException we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.isBooleanPropertyThrowsException()) { + failWithMessage("\nExpecting that actual BeanWithOneException is not boolean property throws exception but is."); + } + // return the current assertion for method chaining return this; } - /** * Verifies that the actual BeanWithOneException's iterablePropertyThrowsException contains the given String elements. @@ -131,14 +169,14 @@ public class BeanWithOneExceptionAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting wheelsCount of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check int actualWheelsCount = actual.getWheelsCount(); if (actualWheelsCount != wheelsCount) { diff --git a/src/test/resources/ClassUsingDifferentClassesWithSameName.expected.txt b/src/test/resources/ClassUsingDifferentClassesWithSameName.expected.txt index 42cb6f7a..363f010b 100644 --- a/src/test/resources/ClassUsingDifferentClassesWithSameName.expected.txt +++ b/src/test/resources/ClassUsingDifferentClassesWithSameName.expected.txt @@ -40,7 +40,7 @@ public class ClassUsingDifferentClassesWithSameNameAssert extends AbstractObject // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting nbaTeam of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check org.assertj.assertions.generator.data.nba.Team actualNbaTeam = actual.getNbaTeam(); if (!Objects.areEqual(actualNbaTeam, nbaTeam)) { @@ -63,7 +63,7 @@ public class ClassUsingDifferentClassesWithSameNameAssert extends AbstractObject // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting team of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check org.assertj.assertions.generator.data.Team actualTeam = actual.getTeam(); if (!Objects.areEqual(actualTeam, team)) { diff --git a/src/test/resources/FieldPropertyClash.expected.txt b/src/test/resources/FieldPropertyClash.expected.txt index 25b9f330..1a2be51d 100644 --- a/src/test/resources/FieldPropertyClash.expected.txt +++ b/src/test/resources/FieldPropertyClash.expected.txt @@ -40,7 +40,7 @@ public class FieldPropertyClashAssert extends AbstractObjectAssert 0) { failWithMessage(assertjErrorMessage, actual, java.util.Arrays.toString(actual.getCase())); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Keywords's catch is equal to the given one. @@ -372,7 +372,7 @@ public class KeywordsAssert extends AbstractObjectAssert expectedConst) { // check that actual Keywords we want to make assertions on is not null. isNotNull(); // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting const of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check - Class actualConst = actual.getConst(); + Class actualConst = actual.getConst(); if (!Objects.areEqual(actualConst, expectedConst)) { failWithMessage(assertjErrorMessage, actual, expectedConst, actualConst); } @@ -441,7 +477,7 @@ public class KeywordsAssert extends AbstractObjectAssert\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualDouble, expectedDouble, offset, Math.abs(expectedDouble - actualDouble)); - + // check Assertions.assertThat(actualDouble).overridingErrorMessage(assertjErrorMessage).isCloseTo(expectedDouble, Assertions.within(offset)); @@ -696,7 +732,7 @@ public class KeywordsAssert extends AbstractObjectAssert\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualFloat, expectedFloat, offset, Math.abs(expectedFloat - actualFloat)); - + // check Assertions.assertThat(actualFloat).overridingErrorMessage(assertjErrorMessage).isCloseTo(expectedFloat, Assertions.within(offset)); @@ -884,7 +920,7 @@ public class KeywordsAssert extends AbstractObjectAssert 0) { failWithMessage(assertjErrorMessage, actual, java.util.Arrays.toString(actual.getSwitch())); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Keywords's synchronized is equal to the given one. @@ -1456,7 +1492,7 @@ public class KeywordsAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting publicCategory of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check Movie.PublicCategory actualPublicCategory = actual.getPublicCategory(); if (!Objects.areEqual(actualPublicCategory, publicCategory)) { @@ -64,7 +64,7 @@ public class MovieAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting releaseDate of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check java.util.Date actualReleaseDate = actual.getReleaseDate(); if (!Objects.areEqual(actualReleaseDate, releaseDate)) { @@ -87,7 +87,7 @@ public class MovieAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting title of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualTitle = actual.getTitle(); if (!Objects.areEqual(actualTitle, title)) { @@ -110,7 +110,7 @@ public class MovieAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting creator of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualCreator = actual.creator; if (!Objects.areEqual(actualCreator, creator)) { @@ -133,7 +133,7 @@ public class MovieAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting producer of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualProducer = actual.producer; if (!Objects.areEqual(actualProducer, producer)) { @@ -157,7 +157,7 @@ public class MovieAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting rating of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - // check + // check value for rating double actualRating = actual.rating; if (actualRating != rating) { failWithMessage(assertjErrorMessage, actual, rating, actualRating); @@ -181,11 +181,11 @@ public class MovieAssert extends AbstractObjectAssert { isNotNull(); double actualRating = actual.rating; - + // overrides the default error message with a more explicit one String assertjErrorMessage = String.format("\nExpecting rating:\n <%s>\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualRating, rating, offset, Math.abs(rating - actualRating)); - + // check Assertions.assertThat(actualRating).overridingErrorMessage(assertjErrorMessage).isCloseTo(rating, Assertions.within(offset)); @@ -202,11 +202,11 @@ public class MovieAssert extends AbstractObjectAssert { // check that actual Movie we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is true if (!actual.xrated) { failWithMessage("\nExpecting that actual Movie is xrated but is not."); } - + // return the current assertion for method chaining return this; } @@ -220,11 +220,11 @@ public class MovieAssert extends AbstractObjectAssert { // check that actual Movie we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is false if (actual.xrated) { failWithMessage("\nExpecting that actual Movie is not xrated but is."); } - + // return the current assertion for method chaining return this; } diff --git a/src/test/resources/NestedClassAssert.hierarchical.template.expected.txt b/src/test/resources/NestedClassAssert.hierarchical.template.expected.txt index e6d6acc9..375a36ad 100644 --- a/src/test/resources/NestedClassAssert.hierarchical.template.expected.txt +++ b/src/test/resources/NestedClassAssert.hierarchical.template.expected.txt @@ -1,6 +1,5 @@ package org.assertj.assertions.generator.data; - /** * {@link ${nestedClass}} specific assertions - Generated by CustomAssertionGenerator. * diff --git a/src/test/resources/NestedClassAssert.template.expected.txt b/src/test/resources/NestedClassAssert.template.expected.txt index 9828244d..518b6d91 100644 --- a/src/test/resources/NestedClassAssert.template.expected.txt +++ b/src/test/resources/NestedClassAssert.template.expected.txt @@ -40,7 +40,7 @@ public class ${nestedClass}Assert extends AbstractObjectAssert<${nestedClass}Ass // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting name of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualName = actual.getName(); if (!Objects.areEqual(actualName, name)) { diff --git a/src/test/resources/PlayerAgentAssert.expected.txt b/src/test/resources/PlayerAgentAssert.expected.txt index a64a647d..5b416498 100644 --- a/src/test/resources/PlayerAgentAssert.expected.txt +++ b/src/test/resources/PlayerAgentAssert.expected.txt @@ -40,7 +40,7 @@ public class PlayerAgentAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting assistsPerGame of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check int actualAssistsPerGame = actual.getAssistsPerGame(); if (actualAssistsPerGame != assistsPerGame) { @@ -53,6 +53,78 @@ public class PlayerAssert extends AbstractObjectAssert { return this; } + /** + * Verifies that the actual Player is disabled. + * @return this assertion object. + * @throws AssertionError - if the actual Player is not disabled. + */ + public PlayerAssert isDisabled() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.isDisabled()) { + failWithMessage("\nExpecting that actual Player is disabled but is not."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player is not disabled. + * @return this assertion object. + * @throws AssertionError - if the actual Player is disabled. + */ + public PlayerAssert isNotDisabled() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.isDisabled()) { + failWithMessage("\nExpecting that actual Player is not disabled but is."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player does not have fun. + * @return this assertion object. + * @throws AssertionError - if the actual Player has fun. + */ + public PlayerAssert doesNotHaveFun() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.doesNotHaveFun()) { + failWithMessage("\nExpecting that actual Player does not have fun but has."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player has fun. + * @return this assertion object. + * @throws AssertionError - if the actual Player does not have fun. + */ + public PlayerAssert hasFun() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.doesNotHaveFun()) { + failWithMessage("\nExpecting that actual Player has fun but does not have."); + } + + // 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. @@ -65,7 +137,7 @@ public class PlayerAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one 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(); if (!Objects.areEqual(actualName, name)) { @@ -76,6 +148,42 @@ public class PlayerAssert extends AbstractObjectAssert { return this; } + /** + * Verifies that the actual Player should not play. + * @return this assertion object. + * @throws AssertionError - if the actual Player should play. + */ + public PlayerAssert shouldNotPlay() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.shouldNotPlay()) { + failWithMessage("\nExpecting that actual Player should not play but should."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player should play. + * @return this assertion object. + * @throws AssertionError - if the actual Player should not play. + */ + public PlayerAssert shouldPlay() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.shouldNotPlay()) { + failWithMessage("\nExpecting that actual Player should play but should not."); + } + + // return the current assertion for method chaining + return this; + } + /** * Verifies that the actual Player's points contains the given int[] elements. * @param points the given elements that should be contained in actual Player's points. @@ -88,14 +196,14 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given int[] varargs is not null. if (points == null) failWithMessage("Expecting points parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.getPoints(), points); // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Player's points contains the given int[] elements in Collection. * @param points the given elements that should be contained in actual Player's points. @@ -111,7 +219,7 @@ public class PlayerAssert extends AbstractObjectAssert { failWithMessage("Expecting points parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.getPoints(), points.toArray()); @@ -131,7 +239,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given int[] varargs is not null. if (points == null) failWithMessage("Expecting points parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.getPoints(), points); @@ -154,7 +262,7 @@ public class PlayerAssert extends AbstractObjectAssert { failWithMessage("Expecting points parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.getPoints(), points.toArray()); @@ -175,7 +283,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given int[] varargs is not null. if (points == null) failWithMessage("Expecting points parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.getPoints(), points); @@ -199,7 +307,7 @@ public class PlayerAssert extends AbstractObjectAssert { failWithMessage("Expecting points parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.getPoints(), points.toArray()); @@ -218,16 +326,16 @@ public class PlayerAssert extends AbstractObjectAssert { // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have points but had :\n <%s>"; - + // check if (actual.getPoints().iterator().hasNext()) { failWithMessage(assertjErrorMessage, actual, actual.getPoints()); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Player's pointsPerGame is equal to the given one. @@ -241,7 +349,7 @@ public class PlayerAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting pointsPerGame of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check int actualPointsPerGame = actual.getPointsPerGame(); if (actualPointsPerGame != pointsPerGame) { @@ -264,7 +372,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given String varargs is not null. if (previousTeams == null) failWithMessage("Expecting previousTeams parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.getPreviousTeams()).contains(previousTeams); @@ -274,7 +382,7 @@ public class PlayerAssert extends AbstractObjectAssert { /** * Verifies that the actual Player's previousTeams contains only the given String elements and nothing else in whatever order. - * + * * @param previousTeams the given elements that should be contained in actual Player's previousTeams. * @return this assertion object. * @throws AssertionError if the actual Player's previousTeams does not contain all given String elements and nothing else. @@ -285,7 +393,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given String varargs is not null. if (previousTeams == null) failWithMessage("Expecting previousTeams parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.getPreviousTeams()).containsOnly(previousTeams); @@ -306,7 +414,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given String varargs is not null. if (previousTeams == null) failWithMessage("Expecting previousTeams parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.getPreviousTeams()).doesNotContain(previousTeams); @@ -325,16 +433,16 @@ public class PlayerAssert extends AbstractObjectAssert { // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have previousTeams but had :\n <%s>"; - - // check + + // check that it is not empty if (actual.getPreviousTeams().length > 0) { failWithMessage(assertjErrorMessage, actual, java.util.Arrays.toString(actual.getPreviousTeams())); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Player's reboundsPerGame is equal to the given one. @@ -348,7 +456,7 @@ public class PlayerAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting reboundsPerGame of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check int actualReboundsPerGame = actual.getReboundsPerGame(); if (actualReboundsPerGame != reboundsPerGame) { @@ -359,6 +467,78 @@ public class PlayerAssert extends AbstractObjectAssert { return this; } + /** + * Verifies that the actual Player is rookie. + * @return this assertion object. + * @throws AssertionError - if the actual Player is not rookie. + */ + public PlayerAssert isRookie() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.isRookie()) { + failWithMessage("\nExpecting that actual Player is rookie but is not."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player is not rookie. + * @return this assertion object. + * @throws AssertionError - if the actual Player is rookie. + */ + public PlayerAssert isNotRookie() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.isRookie()) { + failWithMessage("\nExpecting that actual Player is not rookie but is."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player was rookie. + * @return this assertion object. + * @throws AssertionError - if the actual Player was not rookie. + */ + public PlayerAssert wasRookie() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.wasRookie()) { + failWithMessage("\nExpecting that actual Player was rookie but was not."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player was not rookie. + * @return this assertion object. + * @throws AssertionError - if the actual Player was rookie. + */ + public PlayerAssert wasNotRookie() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.wasRookie()) { + failWithMessage("\nExpecting that actual Player was not rookie but was."); + } + + // return the current assertion for method chaining + return this; + } + /** * Verifies that the actual Player's size is equal to the given one. * @param size the given size to compare the actual Player's size to. @@ -372,7 +552,7 @@ public class PlayerAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting size of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - // check + // check value for size float actualSize = actual.getSize(); if (actualSize != size) { failWithMessage(assertjErrorMessage, actual, size, actualSize); @@ -396,11 +576,11 @@ public class PlayerAssert extends AbstractObjectAssert { isNotNull(); float actualSize = actual.getSize(); - + // overrides the default error message with a more explicit one String assertjErrorMessage = String.format("\nExpecting size:\n <%s>\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualSize, size, offset, Math.abs(size - actualSize)); - + // check Assertions.assertThat(actualSize).overridingErrorMessage(assertjErrorMessage).isCloseTo(size, Assertions.within(offset)); @@ -420,7 +600,7 @@ public class PlayerAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting team of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualTeam = actual.getTeam(); if (!Objects.areEqual(actualTeam, team)) { @@ -443,14 +623,14 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given Player varargs is not null. if (teamMates == null) failWithMessage("Expecting teamMates parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.getTeamMates(), teamMates); // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Player's teamMates contains the given Player elements in Collection. * @param teamMates the given elements that should be contained in actual Player's teamMates. @@ -466,7 +646,7 @@ public class PlayerAssert extends AbstractObjectAssert { failWithMessage("Expecting teamMates parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.getTeamMates(), teamMates.toArray()); @@ -486,7 +666,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given Player varargs is not null. if (teamMates == null) failWithMessage("Expecting teamMates parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.getTeamMates(), teamMates); @@ -509,7 +689,7 @@ public class PlayerAssert extends AbstractObjectAssert { failWithMessage("Expecting teamMates parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.getTeamMates(), teamMates.toArray()); @@ -530,7 +710,7 @@ public class PlayerAssert extends AbstractObjectAssert { // check that given Player varargs is not null. if (teamMates == null) failWithMessage("Expecting teamMates parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.getTeamMates(), teamMates); @@ -554,7 +734,7 @@ public class PlayerAssert extends AbstractObjectAssert { failWithMessage("Expecting teamMates parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.getTeamMates(), teamMates.toArray()); @@ -573,85 +753,157 @@ public class PlayerAssert extends AbstractObjectAssert { // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have teamMates but had :\n <%s>"; - + // check if (actual.getTeamMates().iterator().hasNext()) { failWithMessage(assertjErrorMessage, actual, actual.getTeamMates()); } - + // return the current assertion for method chaining return this; } - + /** - * Verifies that the actual Player is disabled. + * Verifies that the actual Player has trophy. * @return this assertion object. - * @throws AssertionError - if the actual Player is not disabled. + * @throws AssertionError - if the actual Player does not have trophy. */ - public PlayerAssert isDisabled() { + public PlayerAssert hasTrophy() { // check that actual Player we want to make assertions on is not null. isNotNull(); - // check - if (!actual.isDisabled()) { - failWithMessage("\nExpecting that actual Player is disabled but is not."); + // check that property call/field access is true + if (!actual.hasTrophy()) { + failWithMessage("\nExpecting that actual Player has trophy but does not have."); } - + // return the current assertion for method chaining return this; } /** - * Verifies that the actual Player is not disabled. + * Verifies that the actual Player does not have trophy. * @return this assertion object. - * @throws AssertionError - if the actual Player is disabled. + * @throws AssertionError - if the actual Player has trophy. */ - public PlayerAssert isNotDisabled() { + public PlayerAssert doesNotHaveTrophy() { // check that actual Player we want to make assertions on is not null. isNotNull(); - // check - if (actual.isDisabled()) { - failWithMessage("\nExpecting that actual Player is not disabled but is."); + // check that property call/field access is false + if (actual.hasTrophy()) { + failWithMessage("\nExpecting that actual Player does not have trophy but has."); } - + // return the current assertion for method chaining return this; } /** - * Verifies that the actual Player is rookie. + * Verifies that the actual Player can win. * @return this assertion object. - * @throws AssertionError - if the actual Player is not rookie. + * @throws AssertionError - if the actual Player cannot win. */ - public PlayerAssert isRookie() { + public PlayerAssert canWin() { // check that actual Player we want to make assertions on is not null. isNotNull(); // check - if (!actual.isRookie()) { - failWithMessage("\nExpecting that actual Player is rookie but is not."); + if (!actual.canWin()) { + failWithMessage("\nExpecting that actual Player can win but cannot."); } - + // return the current assertion for method chaining return this; } /** - * Verifies that the actual Player is not rookie. + * Verifies that the actual Player cannot win. * @return this assertion object. - * @throws AssertionError - if the actual Player is rookie. + * @throws AssertionError - if the actual Player can win. */ - public PlayerAssert isNotRookie() { + public PlayerAssert cannotWin() { // check that actual Player we want to make assertions on is not null. isNotNull(); // check - if (actual.isRookie()) { - failWithMessage("\nExpecting that actual Player is not rookie but is."); + if (!actual.cannotWin()) { + failWithMessage("\nExpecting that actual Player cannot win but can."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player should win. + * @return this assertion object. + * @throws AssertionError - if the actual Player should not win. + */ + public PlayerAssert shouldWin() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.shouldWin()) { + failWithMessage("\nExpecting that actual Player should win but should not."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player should not win. + * @return this assertion object. + * @throws AssertionError - if the actual Player should win. + */ + public PlayerAssert shouldNotWin() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.shouldWin()) { + failWithMessage("\nExpecting that actual Player should not win but should."); } - + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player will win. + * @return this assertion object. + * @throws AssertionError - if the actual Player will not win. + */ + public PlayerAssert willWin() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is true + if (!actual.willWin()) { + failWithMessage("\nExpecting that actual Player will win but will not."); + } + + // return the current assertion for method chaining + return this; + } + + /** + * Verifies that the actual Player will not win. + * @return this assertion object. + * @throws AssertionError - if the actual Player will win. + */ + public PlayerAssert willNotWin() { + // check that actual Player we want to make assertions on is not null. + isNotNull(); + + // check that property call/field access is false + if (actual.willWin()) { + failWithMessage("\nExpecting that actual Player will not win but will."); + } + // return the current assertion for method chaining return this; } diff --git a/src/test/resources/PrimitivesAssert.expected.txt b/src/test/resources/PrimitivesAssert.expected.txt index 4c31c4e3..759e6152 100644 --- a/src/test/resources/PrimitivesAssert.expected.txt +++ b/src/test/resources/PrimitivesAssert.expected.txt @@ -29,6 +29,78 @@ public class PrimitivesAssert extends AbstractObjectAssert\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualDouble, expectedDouble, offset, Math.abs(expectedDouble - actualDouble)); - + // check Assertions.assertThat(actualDouble).overridingErrorMessage(assertjErrorMessage).isCloseTo(expectedDouble, Assertions.within(offset)); @@ -207,11 +279,11 @@ public class PrimitivesAssert extends AbstractObjectAssert\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualDoubleWrapper, doubleWrapper, offset, Math.abs(doubleWrapper - actualDoubleWrapper)); - + // check Assertions.assertThat(actualDoubleWrapper).overridingErrorMessage(assertjErrorMessage).isCloseTo(doubleWrapper, Assertions.within(offset)); @@ -219,6 +291,42 @@ public class PrimitivesAssert extends AbstractObjectAssert\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualFloat, expectedFloat, offset, Math.abs(expectedFloat - actualFloat)); - + // check Assertions.assertThat(actualFloat).overridingErrorMessage(assertjErrorMessage).isCloseTo(expectedFloat, Assertions.within(offset)); @@ -305,11 +413,11 @@ public class PrimitivesAssert extends AbstractObjectAssert\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualFloatWrapper, floatWrapper, offset, Math.abs(floatWrapper - actualFloatWrapper)); - + // check Assertions.assertThat(actualFloatWrapper).overridingErrorMessage(assertjErrorMessage).isCloseTo(floatWrapper, Assertions.within(offset)); @@ -329,7 +437,7 @@ public class PrimitivesAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting division of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualDivision = actual.getDivision(); if (!Objects.areEqual(actualDivision, division)) { @@ -65,7 +65,7 @@ public class TeamAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting name of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // null safe check String actualName = actual.name; if (!Objects.areEqual(actualName, name)) { @@ -88,7 +88,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given String varargs is not null. if (oldNames == null) failWithMessage("Expecting oldNames parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.oldNames).contains(oldNames); @@ -109,7 +109,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given String varargs is not null. if (oldNames == null) failWithMessage("Expecting oldNames parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.oldNames).containsOnly(oldNames); @@ -130,7 +130,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given String varargs is not null. if (oldNames == null) failWithMessage("Expecting oldNames parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Assertions.assertThat(actual.oldNames).doesNotContain(oldNames); @@ -149,16 +149,16 @@ public class TeamAssert extends AbstractObjectAssert { // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have oldNames but had :\n <%s>"; - - // check + + // check that it is not empty if (actual.oldNames.length > 0) { failWithMessage(assertjErrorMessage, actual, java.util.Arrays.toString(actual.oldNames)); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Team's players contains the given org.assertj.assertions.generator.data.nba.Player elements. @@ -172,14 +172,14 @@ public class TeamAssert extends AbstractObjectAssert { // check that given org.assertj.assertions.generator.data.nba.Player varargs is not null. if (players == null) failWithMessage("Expecting players parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.players, players); // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Team's players contains the given org.assertj.assertions.generator.data.nba.Player elements in Collection. * @param players the given elements that should be contained in actual Team's players. @@ -195,7 +195,7 @@ public class TeamAssert extends AbstractObjectAssert { failWithMessage("Expecting players parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.players, players.toArray()); @@ -215,7 +215,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given org.assertj.assertions.generator.data.nba.Player varargs is not null. if (players == null) failWithMessage("Expecting players parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.players, players); @@ -238,7 +238,7 @@ public class TeamAssert extends AbstractObjectAssert { failWithMessage("Expecting players parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.players, players.toArray()); @@ -259,7 +259,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given org.assertj.assertions.generator.data.nba.Player varargs is not null. if (players == null) failWithMessage("Expecting players parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.players, players); @@ -283,7 +283,7 @@ public class TeamAssert extends AbstractObjectAssert { failWithMessage("Expecting players parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.players, players.toArray()); @@ -302,16 +302,16 @@ public class TeamAssert extends AbstractObjectAssert { // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have players but had :\n <%s>"; - + // check if (actual.players.iterator().hasNext()) { failWithMessage(assertjErrorMessage, actual, actual.players); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Team's points contains the given int[] elements. @@ -325,14 +325,14 @@ public class TeamAssert extends AbstractObjectAssert { // check that given int[] varargs is not null. if (points == null) failWithMessage("Expecting points parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.points, points); // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Team's points contains the given int[] elements in Collection. * @param points the given elements that should be contained in actual Team's points. @@ -348,7 +348,7 @@ public class TeamAssert extends AbstractObjectAssert { failWithMessage("Expecting points parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContains(info, actual.points, points.toArray()); @@ -368,7 +368,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given int[] varargs is not null. if (points == null) failWithMessage("Expecting points parameter not to be null."); - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.points, points); @@ -391,7 +391,7 @@ public class TeamAssert extends AbstractObjectAssert { failWithMessage("Expecting points parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message, to set another message call: info.overridingErrorMessage("my error message"); Iterables.instance().assertContainsOnly(info, actual.points, points.toArray()); @@ -412,7 +412,7 @@ public class TeamAssert extends AbstractObjectAssert { // check that given int[] varargs is not null. if (points == null) failWithMessage("Expecting points parameter not to be null."); - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.points, points); @@ -436,7 +436,7 @@ public class TeamAssert extends AbstractObjectAssert { failWithMessage("Expecting points parameter not to be null."); return this; // to fool Eclipse "Null pointer access" warning on toArray. } - + // check with standard error message (use overridingErrorMessage before contains to set your own message). Iterables.instance().assertDoesNotContain(info, actual.points, points.toArray()); @@ -455,16 +455,16 @@ public class TeamAssert extends AbstractObjectAssert { // we override the default error message with a more explicit one String assertjErrorMessage = "\nExpecting :\n <%s>\nnot to have points but had :\n <%s>"; - + // check if (actual.points.iterator().hasNext()) { failWithMessage(assertjErrorMessage, actual, actual.points); } - + // return the current assertion for method chaining return this; } - + /** * Verifies that the actual Team's rank is equal to the given one. @@ -478,7 +478,7 @@ public class TeamAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting rank of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check int actualRank = actual.rank; if (actualRank != rank) { @@ -502,7 +502,7 @@ public class TeamAssert extends AbstractObjectAssert { // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting victoryRatio of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - // check + // check value for victoryRatio double actualVictoryRatio = actual.victoryRatio; if (actualVictoryRatio != victoryRatio) { failWithMessage(assertjErrorMessage, actual, victoryRatio, actualVictoryRatio); @@ -526,11 +526,11 @@ public class TeamAssert extends AbstractObjectAssert { isNotNull(); double actualVictoryRatio = actual.victoryRatio; - + // overrides the default error message with a more explicit one String assertjErrorMessage = String.format("\nExpecting victoryRatio:\n <%s>\nto be close to:\n <%s>\nby less than <%s> but difference was <%s>", actualVictoryRatio, victoryRatio, offset, Math.abs(victoryRatio - actualVictoryRatio)); - + // check Assertions.assertThat(actualVictoryRatio).overridingErrorMessage(assertjErrorMessage).isCloseTo(victoryRatio, Assertions.within(offset)); @@ -547,11 +547,11 @@ public class TeamAssert extends AbstractObjectAssert { // check that actual Team we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is true if (!actual.westCoast) { failWithMessage("\nExpecting that actual Team is westCoast but is not."); } - + // return the current assertion for method chaining return this; } @@ -565,11 +565,11 @@ public class TeamAssert extends AbstractObjectAssert { // check that actual Team we want to make assertions on is not null. isNotNull(); - // check + // check that property call/field access is false if (actual.westCoast) { failWithMessage("\nExpecting that actual Team is not westCoast but is."); } - + // return the current assertion for method chaining return this; } diff --git a/src/test/resources/customtemplates/custom_has_assertion_template_for_whole_number.txt b/src/test/resources/customtemplates/custom_has_assertion_template_for_whole_number.txt index f79a1301..79603821 100644 --- a/src/test/resources/customtemplates/custom_has_assertion_template_for_whole_number.txt +++ b/src/test/resources/customtemplates/custom_has_assertion_template_for_whole_number.txt @@ -13,7 +13,7 @@ // overrides the default error message with a more explicit one String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>"; - + // check ${propertyType} actual${Property} = actual.get${Property}(); if (actual${Property} != ${property_safe}) { From 1a62fe0115227bec5e861bdfe5df03289e66acfb Mon Sep 17 00:00:00 2001 From: Kevin Brightwell Date: Fri, 26 May 2017 00:18:18 -0400 Subject: [PATCH 2/5] Added additional tests and documentation for TypeUtil * Added more tests and documentation for `TypeUtil` * Fixed misc warnings * Added `${propertyType_parameter}` type that is replaced with the "flexible" parameter types when dealing with generics * Fixed strange "space" issue in javadoc comments templates -- I think it's IntelliJ's fault (via my settings?) --- .../generator/BaseAssertionGenerator.java | 28 ++- .../description/ClassDescription.java | 2 +- .../description/DataDescription.java | 8 +- .../description/FieldDescription.java | 2 +- .../description/GetterDescription.java | 2 +- .../ClassToClassDescriptionConverter.java | 2 +- .../assertions/generator/util/ClassUtil.java | 2 +- .../assertions/generator/util/TypeUtil.java | 218 ++++++++++++------ .../templates/has_assertion_template.txt | 2 +- .../has_assertion_template_for_char.txt | 2 +- .../has_assertion_template_for_character.txt | 2 +- .../has_assertion_template_for_primitive.txt | 2 +- ...sertion_template_for_primitive_wrapper.txt | 2 +- ...has_assertion_template_for_real_number.txt | 4 +- ...rtion_template_for_real_number_wrapper.txt | 4 +- ...as_assertion_template_for_whole_number.txt | 2 +- ...tion_template_for_whole_number_wrapper.txt | 2 +- ..._elements_assertion_template_for_array.txt | 2 +- .../generator/AssertionGeneratorTest.java | 2 +- .../description/FieldDescriptionTest.java | 2 +- .../description/GetterDescriptionTest.java | 2 +- .../ClassToClassDescriptionConverterTest.java | 2 +- .../generator/util/TypeUtilTest.java | 120 +++++++++- .../BeanWithOneException.expected.txt | 2 +- src/test/resources/Keywords.expected.txt | 4 +- src/test/resources/TeamAssert.expected.txt | 2 +- 26 files changed, 312 insertions(+), 112 deletions(-) diff --git a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java index aed34e94..5cc6d5b7 100644 --- a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java @@ -1,4 +1,4 @@ -/* +/** * 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 * @@ -28,7 +28,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static com.google.common.base.Preconditions.checkState; import static java.lang.String.format; import static org.apache.commons.lang3.StringUtils.*; import static org.assertj.assertions.generator.Template.Type.ASSERT_CLASS; @@ -55,6 +54,7 @@ public class BaseAssertionGenerator implements AssertionGenerator, AssertionsEnt private static final String PROPERTY_WITH_SAFE = "${property_safe}"; private static final String PACKAGE = "${package}"; private static final String PROPERTY_TYPE = "${propertyType}"; + private static final String PROPERTY_TYPE_PARAM = "${propertyType_parameter}"; private static final String PROPERTY_SIMPLE_TYPE = "${propertySimpleType}"; private static final String PROPERTY_ASSERT_TYPE = "${propertyAssertType}"; private static final String CLASS_TO_ASSERT = "${class_to_assert}"; @@ -119,7 +119,6 @@ public void setDirectoryWhereAssertionFilesAreGenerated(String targetBaseDirecto @Override public File generateCustomAssertionFor(ClassDescription classDescription) throws IOException { - // Assertion content String assertionFileContent = generateCustomAssertionContentFor(classDescription); // finally create the assertion file, located in its package directory starting from targetBaseDirectory @@ -506,7 +505,9 @@ private String assertionContentForField(FieldDescription field, ClassDescription assertionContent = replace(assertionContent, PROPERTY_ASSERT_TYPE, field.getAssertTypeName(classDescription.getPackageName())); assertionContent = replace(assertionContent, PROPERTY_TYPE, - field.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName())); + field.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName(), false)); + assertionContent = replace(assertionContent, PROPERTY_TYPE_PARAM, + field.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName(), true)); assertionContent = replace(assertionContent, PROPERTY_WITH_LOWERCASE_FIRST_CHAR, fieldName); // It should not be possible to have a field that is a keyword - compiler won't allow it. assertionContent = replace(assertionContent, PROPERTY_WITH_SAFE, fieldName); @@ -608,7 +609,9 @@ private String assertionContentForProperty(GetterDescription getter, ClassDescri assertionContent = replace(assertionContent, PROPERTY_ASSERT_TYPE, getter.getAssertTypeName(classDescription.getPackageName())); assertionContent = replace(assertionContent, PROPERTY_TYPE, - getter.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName())); + getter.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName(), false)); + assertionContent = replace(assertionContent, PROPERTY_TYPE_PARAM, + getter.getFullyQualifiedTypeNameIfNeeded(classDescription.getPackageName(), true)); assertionContent = replace(assertionContent, PROPERTY_WITH_LOWERCASE_FIRST_CHAR, propertyName); assertionContent = replace(assertionContent, PROPERTY_WITH_SAFE, getSafeProperty(propertyName)); return assertionContent; @@ -692,7 +695,7 @@ private String declareExceptions(GetterDescription getter, String assertionConte if (first) throwsClause.append("throws "); else throwsClause.append(", "); first = false; - String exceptionName = TypeUtil.getFullyQualifiedTypeNameIfNeeded(exception, classDescription.getPackageName()); + String exceptionName = TypeUtil.getTypeDeclarationWithinPackage(exception, classDescription.getPackageName(), false); throwsClause.append(exceptionName); throwsJavaDoc.append(LINE_SEPARATOR).append(" * @throws ").append(exceptionName); throwsJavaDoc.append(" if actual.").append("${getter}() throws one."); @@ -712,8 +715,11 @@ private void fillFile(String customAssertionContent, File assertionJavaFile) thr private File createFile(String fileContent, String fileName, String targetDirectory) throws IOException { File file = new File(targetDirectory, fileName); - checkState(file.createNewFile(), - "Could not create file: dir=%s, file=%s", targetDirectory, fileName); + + // Ignore the result as it only returns false when the file existed previously + // which is not _wrong_. + //noinspection ResultOfMethodCallIgnored + file.createNewFile(); fillFile(fileContent, file); return file; } @@ -723,8 +729,10 @@ private static boolean noClassDescriptionsGiven(final Set clas } private static void buildTargetDirectory(String targetDirectory) { - checkState(new File(targetDirectory).mkdirs(), - "Could not create targetDirectory: %s", targetDirectory); + //noinspection ResultOfMethodCallIgnored + // Ignore the result as it only returns true iff the dir was created, false is + // not bad. + new File(targetDirectory).mkdirs(); } @Override diff --git a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java index 9ffbfe3b..08e746ac 100644 --- a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java index f0aaf935..947f21f5 100644 --- a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * @@ -192,10 +192,10 @@ public String getNegativePredicate() { */ public String getElementTypeName(String packageName) { if (valueType.isArray()) { - return TypeUtil.getFullyQualifiedTypeNameIfNeeded(valueType.getComponentType(), packageName); + return TypeUtil.getTypeDeclarationWithinPackage(valueType.getComponentType(), packageName, false); } else if (valueType.isSubtypeOf(Iterable.class)) { TypeToken componentType = valueType.resolveType(Iterable.class.getTypeParameters()[0]); - return TypeUtil.getFullyQualifiedTypeNameIfNeeded(componentType, packageName); + return TypeUtil.getTypeDeclarationWithinPackage(componentType, packageName, false); } return null; @@ -206,7 +206,7 @@ public String getElementAssertTypeName(String packageName) { return elementType == null ? null : TypeUtil.getAssertType(elementType, packageName); } - public String getFullyQualifiedTypeNameIfNeeded(String packageName) { + public String getFullyQualifiedTypeNameIfNeeded(String packageName, final boolean asParameter) { return TypeUtil.getTypeDeclarationWithinPackage(valueType, packageName, false); } diff --git a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java index 73a78c11..cfb856e4 100644 --- a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java index b13ba173..edd30646 100644 --- a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java b/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java index 53243213..7132aa60 100644 --- a/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java +++ b/src/main/java/org/assertj/assertions/generator/description/converter/ClassToClassDescriptionConverter.java @@ -1,4 +1,4 @@ -/* +/** * 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 * 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 e8e321a1..237d4aca 100644 --- a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java b/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java index 505dbb12..777594c5 100644 --- a/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java @@ -1,4 +1,4 @@ -/* +/** * 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 * @@ -30,38 +30,40 @@ */ public class TypeUtil { - public static final Package JAVA_LANG_PACKAGE = Object.class.getPackage(); + private static final Package JAVA_LANG_PACKAGE = Object.class.getPackage(); /** - * return the simple element valueType name if element valueType belongs to given the package and the fully qualified element - * valueType name otherwise. + * Checks if the package, {@code child} is under the package {@code parent}. + * @param child Child package + * @param parent Parent package + * @return True iff the child package is under the parent, false if not or either is {@code null}. * - * @param packageName typically the package of the enclosing Class - * @return the simple element valueType name if element valueType belongs to given the package and the fully qualified element - * valueType name otherwise. + * @see #isInnerPackageOf(String, String) String argument equivalent */ - public static String getFullyQualifiedTypeNameIfNeeded(TypeToken type, String packageName) { - Package toCheck = Package.getPackage(packageName); - return getFullyQualifiedTypeNameIfNeeded(type, toCheck); + public static boolean isInnerPackageOf(Package child, Package parent) { + return child != null && parent != null + && child.getName().startsWith(parent.getName()); } /** - * return the simple element valueType name if element valueType belongs to given the package and the fully qualified element - * valueType name otherwise. + * Utility version that allows to pass a string and {@link Package}. + *
+ * Delegates to {@link #isInnerPackageOf(String, String)}. * - * @param toCheck typically the package of the enclosing Class - * @return the simple element valueType name if element valueType belongs to given the package and the fully qualified element - * valueType name otherwise. + * @see #isInnerPackageOf(String, String) */ - public static String getFullyQualifiedTypeNameIfNeeded(TypeToken type, Package toCheck) { - return getTypeDeclarationWithinPackage(type, (toCheck == null ? null : toCheck.getName()), false); - } - - public static boolean isInnerPackageOf(Package child, Package parent) { - return child != null && parent != null && child.getName().startsWith(parent.getName()); - + public static boolean isInnerPackageOf(Package child, String parent) { + return child != null && isInnerPackageOf(child.getName(), parent); } + /** + * Checks if the package, {@code child} is under the package {@code parent}. + * @param parentPackage Parent package + * @param childPackage Child package + * @return True iff the child package is under the parent, false if not or either is {@code null}. + * + * @see #isInnerPackageOf(String, String) String argument equivalent + */ public static boolean isInnerPackageOf(String childPackage, String parentPackage) { checkArgument(!Strings.isNullOrEmpty(childPackage), "childPackage is null or empty"); checkNotNull(parentPackage, "parentPackage is null or empty"); @@ -70,15 +72,34 @@ public static boolean isInnerPackageOf(String childPackage, String parentPackage } + /** + * Checks if the type passed is a member of {@code java.lang} or is a "built-in" type (e.g. primitive or array). + * @return true if part of java language + */ public static boolean isJavaLangType(TypeToken type) { return type.isPrimitive() || type.isArray() || Objects.equals(JAVA_LANG_PACKAGE, type.getRawType().getPackage()); } + /** + * Checks if the type passed is a member of {@code java.lang} or is a "built-in" type (e.g. primitive or array). + * @return true if part of java language + * + * @see #isJavaLangType(TypeToken) + */ public static boolean isJavaLangType(Type type) { return isJavaLangType(TypeToken.of(type)); } - + /** + * Generates a "type declaration" that could be used in Java code based on the {@code type} and if it is a parameter, + * it will try to be as "flexible" as possible. + * + * @param type Type to get declaration for + * @param asParameter True if the type is being used as a parameter + * @return String representation of the type + * + * @see #getTypeDeclaration(TypeToken, boolean, boolean) + */ public static String getTypeDeclaration(TypeToken type, final boolean asParameter, boolean fullyQualified) { StringBuilder bld = new StringBuilder(); Class raw = type.getRawType(); @@ -89,10 +110,12 @@ public static String getTypeDeclaration(TypeToken type, final boolean asParam /** * Uses the package name as a "local package" and tries to discern whether or not to generate * fully qualified names. - * @param type - * @param packageName - * @param asParameter - * @return + * @param type Type to get declaration for + * @param packageName local package name + * @param asParameter True if the type is being used as a parameter + * @return String representation of the type + * + * @see #getTypeDeclaration(TypeToken, boolean, boolean) */ public static String getTypeDeclarationWithinPackage(TypeToken type, String packageName, final boolean asParameter) { @@ -104,7 +127,12 @@ public static String getTypeDeclarationWithinPackage(TypeToken type, String p } - public static void getTypeDeclaration(StringBuilder bld, String basePackage, TypeToken type, boolean asParameter, boolean fullyQualified) { + /** + * helper method for {@code #getTypeDeclarationXXX()} + * @see #getTypeDeclaration(TypeToken, boolean, boolean) + * @see #getTypeDeclarationWithinPackage(TypeToken, String, boolean) + */ + private static void getTypeDeclaration(StringBuilder bld, String basePackage, TypeToken type, boolean asParameter, boolean fullyQualified) { Class raw = type.getRawType(); @@ -133,85 +161,127 @@ public static void getTypeDeclaration(StringBuilder bld, String basePackage, Typ bld.append(raw.getSimpleName()); + // Now handle generics if (raw.getTypeParameters().length > 0) { bld.append("<"); + boolean first = true; for (TypeVariable tv : raw.getTypeParameters()) { + // only append at the end + if (!first) { + bld.append(','); + } + first = false; + TypeToken paramType = type.resolveType(tv); Class rawParam = paramType.getRawType(); + String typeString = StringUtils.removeAll(paramType.toString(), "capture#\\d+-of\\s+"); + typeString = typeString.replace("(\\?\\s+extends\\s+){2,}", "? extends "); - if (rawParam.equals(Object.class)) { - bld.append("?"); - } else { - if (asParameter && !rawParam.equals(Object.class) && tv.getBounds().length > 0) { - String typeString = StringUtils.removeAll(paramType.toString(), "capture#\\d+-of\\s+"); - typeString = typeString.replace("(\\?\\s+extends\\s+){2,}", "? extends "); - - if (!typeString.contains("?")) { - bld.append("? extends "); - } + boolean isWildCard = typeString.contains("?"); - // fall through - } + // Some specializations need to be done to make sure that the arguments + // are property pulled out and written - Package paramPackage = paramType.getRawType().getPackage(); + // If its a wild card and it has no boundary other than Object, + // we just use the wild card + if (isWildCard && rawParam.equals(Object.class)) { + bld.append("?"); + continue; + } - getTypeDeclaration(bld, basePackage, paramType, asParameter, - fullyQualified - || ((paramPackage != null && !Objects.equals(basePackage, paramPackage.getName())) - && Objects.equals(paramPackage, raw.getPackage()))); + if (asParameter) { + // We handle parameters differently so that it's accepted more "flexibility" + bld.append("? extends "); } - bld.append(","); + // now we recursively add the type parameter, we set `asParameter` to false + // because odds are it will become wrong to keep adding the "extends" boundaries + Package paramPackage = paramType.getRawType().getPackage(); + + getTypeDeclaration(bld, basePackage, paramType, false, + fullyQualified + || ((paramPackage != null && !Objects.equals(basePackage, paramPackage.getName())) + && Objects.equals(paramPackage, raw.getPackage()))); } - bld.deleteCharAt(bld.length() - 1); bld.append(">"); } } } + /** + * Gets the name of the class that will be the "assert". + * @param type Type being tested + * @param packageName package this type will reside in + * @return Name for "assert" type + */ // used to support navigation assertion // https://github.com/joel-costigliola/assertj-assertions-generator/issues/67 public static String getAssertType(TypeToken type, String packageName) { - Class raw = type.getRawType(); - Package typePackage = raw.getPackage(); + TypeToken wrapped = type.wrap(); + Class raw = wrapped.getRawType(); - if (isInnerPackageOf(typePackage, Package.getPackage("java"))) { + String typeName = null; + if (isJavaLangType(wrapped)) { try { - String name = "org.assertj.core.api." + raw.getSimpleName() + "Assert"; + String builtInName = "org.assertj.core.api." + raw.getSimpleName() + "Assert"; // try to get the class, if it exists, then we know its valid - Class.forName(name); + Class.forName(builtInName); - return name; + typeName = builtInName.substring(0, builtInName.length() - "Assert".length()); } catch (ClassNotFoundException cfne) { - // it wasn't found, this means the class doesn't exist, so fall back + // it wasn't found, this means the class doesn't exist, so fall through } } - String typeName = resolveTypeNameInPackage(type, packageName); - return typeName + "Assert"; - } + if (typeName == null) { + typeName = type.getRawType().getName(); + } - public static String resolveTypeNameInPackage(TypeToken type, Package currentPackage) { - Class raw = type.getRawType(); + return resolveTypeNameInPackage(typeName + "Assert", packageName); + } - if (Objects.equals(raw.getPackage(), currentPackage)) { - return raw.getSimpleName(); - } else { - return raw.getName(); + /** + * Gets the name of a type without the package if {@code currentPackage} is the same as + * {@link Class#getPackage() type's package}. + * + * @param type Type to import + * @param currentPackage package context for the string + * @return String Name resolved within the package + */ + public static String resolveTypeNameInPackage(TypeToken type, String currentPackage) { + // we special case java.lang types because they never need a FQN. + if (isJavaLangType(type)) { + return type.getRawType().getSimpleName(); } + + return resolveTypeNameInPackage(type.getRawType().getName(), currentPackage); } - public static String resolveTypeNameInPackage(TypeToken type, String currentPackage) { - return resolveTypeNameInPackage(type, - checkNotNull(Package.getPackage(currentPackage), - "Package %s does not exist", currentPackage)); + /** + * Gets the name of a type without the package if {@code currentPackage} is the same as + * {@link Class#getPackage() type's package}. + * + * @param type Type to import + * @param currentPackage package context for the string + * @return String Name resolved within the package + */ + public static String resolveTypeNameInPackage(Type type, String currentPackage) { + return resolveTypeNameInPackage(TypeToken.of(type), currentPackage); } - public static String resolveTypeNameInPackage(String type, String currentPackage) { - if (type.startsWith(currentPackage)) { + /** + * Gets the name of a type without the package if {@code currentPackage} is the same as + * {@link Class#getPackage() type's package}. + * + * @param type Type to import + * @param currentPackage package context for the string + * @return Name resolved within the package + */ + private static String resolveTypeNameInPackage(String type, String currentPackage) { + if (!Strings.isNullOrEmpty(currentPackage) && type.startsWith(currentPackage)) { return type.substring(currentPackage.length() + 1, type.length()); } else { return type; @@ -220,6 +290,11 @@ public static String resolveTypeNameInPackage(String type, String currentPackage private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * Gets a type name without any dots in it if they are present -- this is for nested classes + * @param typeName String name of the type + * @return Type without any {@code '.'} characters + */ public static String getTypeNameWithoutDots(String typeName) { int indexOfClassName = indexOfAny(typeName, CAPITAL_LETTERS); final String typeSimpleNameWithOuterClass; @@ -233,6 +308,11 @@ public static String getTypeNameWithoutDots(String typeName) { return remove(typeSimpleNameWithOuterClass, "."); } + /** + * Checks if a type is a boolean type + * @param type Type to check + * @return true iff the type is a boolean. + */ public static boolean isBoolean(TypeToken type) { TypeToken unwrapped = type.unwrap(); return unwrapped.isSubtypeOf(boolean.class); diff --git a/src/main/resources/templates/has_assertion_template.txt b/src/main/resources/templates/has_assertion_template.txt index 8a912372..500f51de 100644 --- a/src/main/resources/templates/has_assertion_template.txt +++ b/src/main/resources/templates/has_assertion_template.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_char.txt b/src/main/resources/templates/has_assertion_template_for_char.txt index 2cd3e6ec..b177edf0 100644 --- a/src/main/resources/templates/has_assertion_template_for_char.txt +++ b/src/main/resources/templates/has_assertion_template_for_char.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_character.txt b/src/main/resources/templates/has_assertion_template_for_character.txt index 8a912372..500f51de 100644 --- a/src/main/resources/templates/has_assertion_template_for_character.txt +++ b/src/main/resources/templates/has_assertion_template_for_character.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_primitive.txt b/src/main/resources/templates/has_assertion_template_for_primitive.txt index 9d48c22c..9dd31d3a 100644 --- a/src/main/resources/templates/has_assertion_template_for_primitive.txt +++ b/src/main/resources/templates/has_assertion_template_for_primitive.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt b/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt index 8a912372..500f51de 100644 --- a/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt +++ b/src/main/resources/templates/has_assertion_template_for_primitive_wrapper.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_real_number.txt b/src/main/resources/templates/has_assertion_template_for_real_number.txt index 07a5eb73..172e98ac 100644 --- a/src/main/resources/templates/has_assertion_template_for_real_number.txt +++ b/src/main/resources/templates/has_assertion_template_for_real_number.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); @@ -31,7 +31,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not close enough to the given value.${throws_javadoc} */ - public ${self_type} has${Property}CloseTo(${propertyType} ${property_safe}, ${propertyType} offset) ${throws}{ + public ${self_type} has${Property}CloseTo(${propertyType_parameter} ${property_safe}, ${propertyType} offset) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt b/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt index bdd95f7d..2d5b0b75 100644 --- a/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt +++ b/src/main/resources/templates/has_assertion_template_for_real_number_wrapper.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); @@ -31,7 +31,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not close enough to the given value.${throws_javadoc} */ - public ${self_type} has${Property}CloseTo(${propertyType} ${property_safe}, ${propertyType} offset) ${throws}{ + public ${self_type} has${Property}CloseTo(${propertyType_parameter} ${property_safe}, ${propertyType} offset) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_whole_number.txt b/src/main/resources/templates/has_assertion_template_for_whole_number.txt index 9d48c22c..9dd31d3a 100644 --- a/src/main/resources/templates/has_assertion_template_for_whole_number.txt +++ b/src/main/resources/templates/has_assertion_template_for_whole_number.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt b/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt index 8a912372..500f51de 100644 --- a/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt +++ b/src/main/resources/templates/has_assertion_template_for_whole_number_wrapper.txt @@ -5,7 +5,7 @@ * @return this assertion object. * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc} */ - public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{ + public ${self_type} has${Property}(${propertyType_parameter} ${property_safe}) ${throws}{ // check that actual ${class_to_assert} we want to make assertions on is not null. isNotNull(); diff --git a/src/main/resources/templates/has_elements_assertion_template_for_array.txt b/src/main/resources/templates/has_elements_assertion_template_for_array.txt index 5277a65d..58826935 100644 --- a/src/main/resources/templates/has_elements_assertion_template_for_array.txt +++ b/src/main/resources/templates/has_elements_assertion_template_for_array.txt @@ -21,7 +21,7 @@ /** * Verifies that the actual ${class_to_assert}'s ${property} contains only the given ${elementType} elements and nothing else in whatever order. - * + * * @param ${property_safe} the given elements that should be contained in actual ${class_to_assert}'s ${property}. * @return this assertion object. * @throws AssertionError if the actual ${class_to_assert}'s ${property} does not contain all given ${elementType} elements and nothing else.${throws_javadoc} diff --git a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java index 7be3df13..52c43a55 100644 --- a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java +++ b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java b/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java index f23182ca..aae6cc6e 100644 --- a/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java +++ b/src/test/java/org/assertj/assertions/generator/description/FieldDescriptionTest.java @@ -1,4 +1,4 @@ -/* +/** * 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 * 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 74800c8f..eacb67f2 100644 --- a/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java +++ b/src/test/java/org/assertj/assertions/generator/description/GetterDescriptionTest.java @@ -1,4 +1,4 @@ -/* +/** * 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 * 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 70f77dac..5910a083 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 @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java b/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java index 35e44315..7a8daf4a 100644 --- a/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java +++ b/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java @@ -1,4 +1,4 @@ -/* +/** * 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 * @@ -15,6 +15,7 @@ import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.AssertionGeneratorTest; import org.assertj.assertions.generator.description.GetterDescriptionTest; +import org.assertj.core.api.BooleanAssert; import org.junit.Test; import java.lang.reflect.Field; @@ -26,6 +27,87 @@ * Describes tests for the {@link TypeUtil} class */ public class TypeUtilTest { + + public static class Inner {} + + @Test + public void resolveTypeNameInPackage() throws Exception { + assertThat(TypeUtil.resolveTypeNameInPackage(String.class, String.class.getPackage().getName())) + .as("java lang type has simple name with package") + .isEqualTo(String.class.getSimpleName()); + assertThat(TypeUtil.resolveTypeNameInPackage(String.class, null)) + .as("java lang type has simple name without package") + .isEqualTo(String.class.getSimpleName()); + + + assertThat(TypeUtil.resolveTypeNameInPackage(TypeUtilTest.class, null)) + .as("normal type has FQN without package") + .isEqualTo(TypeUtilTest.class.getName()); + assertThat(TypeUtil.resolveTypeNameInPackage(TypeUtilTest.class, TypeUtilTest.class.getPackage().getName())) + .as("normal type does not has FQN with package") + .isEqualTo(TypeUtilTest.class.getSimpleName()); + assertThat(TypeUtil.resolveTypeNameInPackage(TypeUtilTest.class, String.class.getPackage().getName())) + .as("normal type does not have FQN with other package") + .isEqualTo(TypeUtilTest.class.getName()); + + + assertThat(TypeUtil.resolveTypeNameInPackage(Inner.class, null)) + .as("inner type has FQN without package") + .isEqualTo(Inner.class.getName()); + assertThat(TypeUtil.resolveTypeNameInPackage(Inner.class, Inner.class.getPackage().getName())) + .as("inner type does not have FQN with package") + .isEqualTo(String.format("%s$%s", TypeUtilTest.class.getSimpleName(), Inner.class.getSimpleName())); + } + + + @Test + public void isJavaLangType() throws Exception { + assertThat(TypeUtil.isJavaLangType(Object.class)).isTrue(); + assertThat(TypeUtil.isJavaLangType(boolean.class)).isTrue(); + assertThat(TypeUtil.isJavaLangType(Boolean.class)).isTrue(); + + // wrong + assertThat(TypeUtil.isJavaLangType(TypeUtilTest.class)).isFalse(); + } + + @Test + public void getAssertType() throws Exception { + TypeToken thisType = TypeToken.of(TypeUtilTest.class); + + assertThat(TypeUtil.getAssertType(thisType, thisType.getRawType().getPackage().getName())) + .as("resolves non-built-in type correctly") + .isEqualTo("TypeUtilTestAssert"); + + TypeToken primitive = TypeToken.of(boolean.class); + assertThat(TypeUtil.getAssertType(primitive, thisType.getRawType().getPackage().getName())) + .as("resolves primitive correctly") + .isEqualTo(BooleanAssert.class.getName()); + + TypeToken wrapper = TypeToken.of(Boolean.class); + assertThat(TypeUtil.getAssertType(wrapper, thisType.getRawType().getPackage().getName())) + .as("resolves primitive wrapper correctly") + .isEqualTo(BooleanAssert.class.getName()); + + assertThat(TypeUtil.getAssertType(wrapper, BooleanAssert.class.getPackage().getName())) + .as("resolves package correctly for built-in package") + .isEqualTo(BooleanAssert.class.getSimpleName()); + } + + @Test + public void getTypeNameWithoutDots() throws Exception { + } + + @Test + public void isBoolean() throws Exception { + TypeToken wrapper = new TypeToken(getClass()) {}; + TypeToken primitive = TypeToken.of(boolean.class); + TypeToken neither = TypeToken.of(TypeUtilTest.class); + + assertThat(TypeUtil.isBoolean(wrapper)).as("for wrapper").isTrue(); + assertThat(TypeUtil.isBoolean(primitive)).as("for primitive").isTrue(); + assertThat(TypeUtil.isBoolean(neither)).as("for non-boolean").isFalse(); + } + @Test public void isInnerPackageOf() throws Exception { @@ -52,6 +134,8 @@ static class Foo { List> listOfFooString; List[]> listOfFooIntArr; List[]> listOfFooIntArrArrArr; + Class clazz; + Class> clazzFoo; } @Test @@ -74,27 +158,55 @@ public void create_generic_type_declaration() throws Exception { expected = String.format("List<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); assertThat(result).isEqualTo(expected); + result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfTField.getGenericType()), true, false); + expected = String.format("List>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + // List of non-T type Field listOfFooStringField = Foo.class.getDeclaredField("listOfFooString"); - result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfFooStringField.getGenericType()), false, false); + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooStringField.getGenericType()), false, false); expected = String.format("List<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); assertThat(result).isEqualTo(expected); + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooStringField.getGenericType()), true, false); + expected = String.format("List>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + // List of Foo[] Field listOfFooIntArr = Foo.class.getDeclaredField("listOfFooIntArr"); - result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfFooIntArr.getGenericType()), false, false); + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooIntArr.getGenericType()), false, false); expected = String.format("List<%s.%s[]>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); assertThat(result).isEqualTo(expected); // List of Foo[] Field listOfFooIntArrArrArr = Foo.class.getDeclaredField("listOfFooIntArrArrArr"); - result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfFooIntArrArrArr.getGenericType()), false, false); + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooIntArrArrArr.getGenericType()), false, false); expected = String.format("List<%s.%s[]>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); assertThat(result).isEqualTo(expected); } + @Test + public void create_wildcard_version() throws Exception { + TypeToken> fooInteger = new TypeToken>(getClass()) {}; + Field clazz = Foo.class.getDeclaredField("clazz"); + String result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazz.getGenericType()), false, true); + String expected = "Class"; + assertThat(result).isEqualTo(expected); + + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazz.getGenericType()), true, false); + assertThat(result).isEqualTo(expected); + + Field clazzFoo = Foo.class.getDeclaredField("clazzFoo"); + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazzFoo.getGenericType()), true, false); + expected = String.format("Class>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazzFoo.getGenericType()), false, false); + expected = String.format("Class<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + } } \ No newline at end of file diff --git a/src/test/resources/BeanWithOneException.expected.txt b/src/test/resources/BeanWithOneException.expected.txt index 51a54657..00864f11 100644 --- a/src/test/resources/BeanWithOneException.expected.txt +++ b/src/test/resources/BeanWithOneException.expected.txt @@ -53,7 +53,7 @@ public class BeanWithOneExceptionAssert extends AbstractObjectAssertonly the given String elements and nothing else in whatever order. - * + * * @param arrayPropertyThrowsException the given elements that should be contained in actual BeanWithOneException's arrayPropertyThrowsException. * @return this assertion object. * @throws AssertionError if the actual BeanWithOneException's arrayPropertyThrowsException does not contain all given String elements and nothing else. diff --git a/src/test/resources/Keywords.expected.txt b/src/test/resources/Keywords.expected.txt index 3f90087f..d5984d31 100644 --- a/src/test/resources/Keywords.expected.txt +++ b/src/test/resources/Keywords.expected.txt @@ -298,7 +298,7 @@ public class KeywordsAssert extends AbstractObjectAssertonly the given Object elements and nothing else in whatever order. - * + * * @param expectedCase the given elements that should be contained in actual Keywords's case. * @return this assertion object. * @throws AssertionError if the actual Keywords's case does not contain all given Object elements and nothing else. @@ -1415,7 +1415,7 @@ public class KeywordsAssert extends AbstractObjectAssertonly the given String elements and nothing else in whatever order. - * + * * @param expectedSwitch the given elements that should be contained in actual Keywords's switch. * @return this assertion object. * @throws AssertionError if the actual Keywords's switch does not contain all given String elements and nothing else. diff --git a/src/test/resources/TeamAssert.expected.txt b/src/test/resources/TeamAssert.expected.txt index 2da8845f..5f9e5210 100644 --- a/src/test/resources/TeamAssert.expected.txt +++ b/src/test/resources/TeamAssert.expected.txt @@ -98,7 +98,7 @@ public class TeamAssert extends AbstractObjectAssert { /** * Verifies that the actual Team's oldNames contains only the given String elements and nothing else in whatever order. - * + * * @param oldNames the given elements that should be contained in actual Team's oldNames. * @return this assertion object. * @throws AssertionError if the actual Team's oldNames does not contain all given String elements and nothing else. From 60bc11715d6154f5347b10f140f9688b0854736d Mon Sep 17 00:00:00 2001 From: Kevin Brightwell Date: Fri, 26 May 2017 00:35:41 -0400 Subject: [PATCH 3/5] Refactor `TypeUtil` into `ClassUtil` * Refactored the `TypeUtil` class into the `ClassUtil` as both serve similar jobs * Fixed more misc. warnings --- .../generator/BaseAssertionGenerator.java | 16 +- .../description/ClassDescription.java | 10 +- .../description/DataDescription.java | 18 +- .../description/FieldDescription.java | 5 +- .../description/GetterDescription.java | 5 +- .../assertions/generator/util/ClassUtil.java | 288 +++++++++++++++- .../assertions/generator/util/TypeUtil.java | 320 ------------------ .../ClassToClassDescriptionConverterTest.java | 8 +- .../generator/util/ClassUtilTest.java | 181 +++++++++- .../generator/util/TypeUtilTest.java | 212 ------------ 10 files changed, 497 insertions(+), 566 deletions(-) delete mode 100644 src/main/java/org/assertj/assertions/generator/util/TypeUtil.java delete mode 100644 src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java diff --git a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java index 5cc6d5b7..db0bd4e2 100644 --- a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -18,7 +18,7 @@ import org.assertj.assertions.generator.description.DataDescription; import org.assertj.assertions.generator.description.FieldDescription; import org.assertj.assertions.generator.description.GetterDescription; -import org.assertj.assertions.generator.util.TypeUtil; +import org.assertj.assertions.generator.util.ClassUtil; import java.io.File; import java.io.FileWriter; @@ -200,7 +200,7 @@ private String fillAssertClassTemplate(String template, ClassDescription classDe // className could be a nested class like "OuterClass.NestedClass", in that case assert class will be // OuterClassNestedClass template = replace(template, SUPER_ASSERTION_CLASS, - TypeUtil.getTypeNameWithoutDots(superAssertionClassName)); + ClassUtil.getTypeNameWithoutDots(superAssertionClassName)); template = replace(template, CLASS_TO_ASSERT, classDescription.getClassNameWithOuterClass()); template = replace(template, SELF_TYPE, selfType); template = replace(template, MYSELF, myself); @@ -386,7 +386,7 @@ private static String assertClassNameOf(ClassDescription classDescription) { } private static String assertClassNameOf(TypeToken type) { - return TypeUtil.getTypeNameWithoutDots(TypeUtil.getTypeDeclaration(type, false, false)) + ASSERT_CLASS_SUFFIX; + return ClassUtil.getTypeNameWithoutDots(ClassUtil.getTypeDeclaration(type, false, false)) + ASSERT_CLASS_SUFFIX; } private static String abstractAssertClassNameOf(ClassDescription classDescription) { @@ -417,8 +417,8 @@ private static String listNeededImports(Set typesToImport, String classP for (String type : typesToImport) { try { Class clazz = Class.forName(type); - if (!clazz.isPrimitive() && !TypeUtil.isJavaLangType(clazz) - && !TypeUtil.isInnerPackageOf(type, classPackage) && !Objects.equals(classPackage, type)) { + if (!clazz.isPrimitive() && !ClassUtil.isJavaLangType(clazz) + && !ClassUtil.isInnerPackageOf(type, classPackage) && !Objects.equals(classPackage, type)) { importsBuilder.append(format(IMPORT_LINE, type, LINE_SEPARATOR)); } } catch (ClassNotFoundException cfne) { @@ -695,7 +695,7 @@ private String declareExceptions(GetterDescription getter, String assertionConte if (first) throwsClause.append("throws "); else throwsClause.append(", "); first = false; - String exceptionName = TypeUtil.getTypeDeclarationWithinPackage(exception, classDescription.getPackageName(), false); + String exceptionName = ClassUtil.getTypeDeclarationWithinPackage(exception, classDescription.getPackageName(), false); throwsClause.append(exceptionName); throwsJavaDoc.append(LINE_SEPARATOR).append(" * @throws ").append(exceptionName); throwsJavaDoc.append(" if actual.").append("${getter}() throws one."); @@ -729,9 +729,9 @@ private static boolean noClassDescriptionsGiven(final Set clas } private static void buildTargetDirectory(String targetDirectory) { - //noinspection ResultOfMethodCallIgnored // Ignore the result as it only returns true iff the dir was created, false is // not bad. + //noinspection ResultOfMethodCallIgnored new File(targetDirectory).mkdirs(); } diff --git a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java index 08e746ac..3404d2a0 100644 --- a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -13,7 +13,7 @@ package org.assertj.assertions.generator.description; import com.google.common.reflect.TypeToken; -import org.assertj.assertions.generator.util.TypeUtil; +import org.assertj.assertions.generator.util.ClassUtil; import java.util.Collection; import java.util.Objects; @@ -51,7 +51,7 @@ public String getClassName() { } public String getFullyQualifiedClassName() { - return TypeUtil.getTypeDeclaration(type, false, true); + return ClassUtil.getTypeDeclaration(type, false, true); } public TypeToken getType() { @@ -59,11 +59,11 @@ public TypeToken getType() { } public String getClassNameWithOuterClass() { - return TypeUtil.getTypeDeclaration(type, false, false); + return ClassUtil.getTypeDeclaration(type, false, false); } public String getClassNameWithOuterClassNotSeparatedByDots() { - return TypeUtil.getTypeNameWithoutDots(getClassNameWithOuterClass()); //classTypeName.getSimpleNameWithOuterClassNotSeparatedByDots(); + return ClassUtil.getTypeNameWithoutDots(getClassNameWithOuterClass()); //classTypeName.getSimpleNameWithOuterClassNotSeparatedByDots(); } public String getPackageName() { diff --git a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java index 947f21f5..999b5b84 100644 --- a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -18,7 +18,7 @@ import com.google.common.primitives.Ints; import com.google.common.primitives.Primitives; import com.google.common.reflect.TypeToken; -import org.assertj.assertions.generator.util.TypeUtil; +import org.assertj.assertions.generator.util.ClassUtil; import java.lang.reflect.Member; import java.util.List; @@ -129,15 +129,15 @@ public TypeToken getValueType() { /** * Get the type of the value stored by the {@link #originalMember} - * @return * @param isFQN Whether or not to get the fully qualified name * @param asParameter if true, this will generate a type-name that is best for * passing as a parameter, for example, for a {@link java.util.Collection Collection} * this would return {@code Collection<? extends String>} instead of * just {@code String} + * @return */ public String getTypeName(boolean isFQN, final boolean asParameter) { - return TypeUtil.getTypeDeclaration(valueType, false, isFQN); + return ClassUtil.getTypeDeclaration(valueType, asParameter, isFQN); } public boolean isIterableType() { @@ -192,10 +192,10 @@ public String getNegativePredicate() { */ public String getElementTypeName(String packageName) { if (valueType.isArray()) { - return TypeUtil.getTypeDeclarationWithinPackage(valueType.getComponentType(), packageName, false); + return ClassUtil.getTypeDeclarationWithinPackage(valueType.getComponentType(), packageName, false); } else if (valueType.isSubtypeOf(Iterable.class)) { TypeToken componentType = valueType.resolveType(Iterable.class.getTypeParameters()[0]); - return TypeUtil.getTypeDeclarationWithinPackage(componentType, packageName, false); + return ClassUtil.getTypeDeclarationWithinPackage(componentType, packageName, false); } return null; @@ -203,15 +203,15 @@ public String getElementTypeName(String packageName) { public String getElementAssertTypeName(String packageName) { TypeToken elementType = valueType.getComponentType(); - return elementType == null ? null : TypeUtil.getAssertType(elementType, packageName); + return elementType == null ? null : ClassUtil.getAssertType(elementType, packageName); } public String getFullyQualifiedTypeNameIfNeeded(String packageName, final boolean asParameter) { - return TypeUtil.getTypeDeclarationWithinPackage(valueType, packageName, false); + return ClassUtil.getTypeDeclarationWithinPackage(valueType, packageName, false); } public String getAssertTypeName(String packageName) { - return TypeUtil.getAssertType(valueType, packageName); + return ClassUtil.getAssertType(valueType, packageName); } public String getPredicateForJavadoc() { diff --git a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java index cfb856e4..ab0aa93e 100644 --- a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -14,7 +14,6 @@ import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.util.ClassUtil; -import org.assertj.assertions.generator.util.TypeUtil; import java.lang.reflect.Field; @@ -62,7 +61,7 @@ public Field getOriginalMember() { @Override public boolean isPredicate() { - return TypeUtil.isBoolean(valueType); + return ClassUtil.isBoolean(valueType); } @Override diff --git a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java index edd30646..46b60b69 100644 --- a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -16,7 +16,6 @@ import com.google.common.reflect.Invokable; import com.google.common.reflect.TypeToken; import org.assertj.assertions.generator.util.ClassUtil; -import org.assertj.assertions.generator.util.TypeUtil; import java.lang.reflect.Method; @@ -69,7 +68,7 @@ public ImmutableList> getExceptions() { @Override public boolean isPredicate() { - return TypeUtil.isBoolean(valueType) && ClassUtil.isValidPredicateName(originalMember.getName()); + return ClassUtil.isBoolean(valueType) && ClassUtil.isValidPredicateName(originalMember.getName()); } public Invokable getInvokable() { 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 237d4aca..f601541a 100644 --- a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -12,6 +12,7 @@ */ package org.assertj.assertions.generator.util; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.reflect.ClassPath; import com.google.common.reflect.ClassPath.ClassInfo; @@ -30,10 +31,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Sets.newLinkedHashSet; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; +import static org.apache.commons.lang3.StringUtils.remove; import static org.apache.commons.lang3.StringUtils.uncapitalize; /** @@ -52,6 +55,8 @@ public int compare(Method m1, Method m2) { return m1.getName().compareTo(m2.getName()); } }; + private static final Package JAVA_LANG_PACKAGE = Object.class.getPackage(); + private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /** * Call {@link #collectClasses(ClassLoader, String...)} with Thread.currentThread().getContextClassLoader() @@ -520,4 +525,285 @@ public static Class getClass(final Type type) { return null; } + /** + * Checks if the package, {@code child} is under the package {@code parent}. + * @param child Child package + * @param parent Parent package + * @return True iff the child package is under the parent, false if not or either is {@code null}. + * + * @see #isInnerPackageOf(String, String) String argument equivalent + */ + public static boolean isInnerPackageOf(Package child, Package parent) { + return child != null && parent != null + && child.getName().startsWith(parent.getName()); + } + + /** + * Utility version that allows to pass a string and {@link Package}. + *
+ * Delegates to {@link #isInnerPackageOf(String, String)}. + * + * @see #isInnerPackageOf(String, String) + */ + public static boolean isInnerPackageOf(Package child, String parent) { + return child != null && isInnerPackageOf(child.getName(), parent); + } + + /** + * Checks if the package, {@code child} is under the package {@code parent}. + * @param parentPackage Parent package + * @param childPackage Child package + * @return True iff the child package is under the parent, false if not or either is {@code null}. + * + * @see #isInnerPackageOf(String, String) String argument equivalent + */ + public static boolean isInnerPackageOf(String childPackage, String parentPackage) { + checkArgument(!Strings.isNullOrEmpty(childPackage), "childPackage is null or empty"); + checkNotNull(parentPackage, "parentPackage is null or empty"); + + return childPackage.startsWith(parentPackage); + } + + /** + * Checks if the type passed is a member of {@code java.lang} or is a "built-in" type (e.g. primitive or array). + * @return true if part of java language + */ + public static boolean isJavaLangType(TypeToken type) { + return type.isPrimitive() || type.isArray() || Objects.equals(JAVA_LANG_PACKAGE, type.getRawType().getPackage()); + } + + /** + * Checks if the type passed is a member of {@code java.lang} or is a "built-in" type (e.g. primitive or array). + * @return true if part of java language + * + * @see #isJavaLangType(TypeToken) + */ + public static boolean isJavaLangType(Type type) { + return isJavaLangType(TypeToken.of(type)); + } + + /** + * Generates a "type declaration" that could be used in Java code based on the {@code type} and if it is a parameter, + * it will try to be as "flexible" as possible. + * + * @param type Type to get declaration for + * @param asParameter True if the type is being used as a parameter + * @return String representation of the type + * + * @see #getTypeDeclaration(TypeToken, boolean, boolean) + */ + public static String getTypeDeclaration(TypeToken type, final boolean asParameter, boolean fullyQualified) { + StringBuilder bld = new StringBuilder(); + Class raw = type.getRawType(); + getTypeDeclaration(bld, (raw.getPackage() == null ? null : raw.getPackage().getName()), type, asParameter, fullyQualified); + return bld.toString(); + } + + /** + * Uses the package name as a "local package" and tries to discern whether or not to generate + * fully qualified names. + * @param type Type to get declaration for + * @param packageName local package name + * @param asParameter True if the type is being used as a parameter + * @return String representation of the type + * + * @see #getTypeDeclaration(TypeToken, boolean, boolean) + */ + public static String getTypeDeclarationWithinPackage(TypeToken type, String packageName, final boolean asParameter) { + + boolean reqFQN = !Objects.equals(packageName, JAVA_LANG_PACKAGE.getName()) + && (!type.isPrimitive() && !type.isArray() && !Objects.equals(packageName, type.getRawType().getPackage().getName())); + StringBuilder bld = new StringBuilder(); + getTypeDeclaration(bld, packageName, type, asParameter, reqFQN); + return bld.toString(); + } + + /** + * helper method for {@code #getTypeDeclarationXXX()} + * @see #getTypeDeclaration(TypeToken, boolean, boolean) + * @see #getTypeDeclarationWithinPackage(TypeToken, String, boolean) + */ + private static void getTypeDeclaration(StringBuilder bld, String basePackage, TypeToken type, boolean asParameter, boolean fullyQualified) { + + Class raw = type.getRawType(); + + // Gotta do some special casing + if (type.isArray()) { + getTypeDeclaration(bld, basePackage, type.getComponentType(), asParameter, fullyQualified); + bld.append("[]"); + } else if (type.isPrimitive()) { + bld.append(raw.toString()); + } else { + // Now we have some types that could be generic, so we have to do more + // to serialize it to the declaration + + if (raw.isMemberClass()) { // inner class + TypeToken outerClass = type.resolveType(raw.getEnclosingClass()); + getTypeDeclaration(bld, basePackage, outerClass, asParameter, fullyQualified); + bld.append("."); + + } else { + // it's a normal class, so just append the package here if needed + if (fullyQualified && !isJavaLangType(type)) { + bld.append(type.getRawType().getPackage().getName()); + bld.append("."); + } + } + + bld.append(raw.getSimpleName()); + + // Now handle generics + if (raw.getTypeParameters().length > 0) { + bld.append("<"); + boolean first = true; + for (TypeVariable tv : raw.getTypeParameters()) { + // only append at the end + if (!first) { + bld.append(','); + } + first = false; + + TypeToken paramType = type.resolveType(tv); + Class rawParam = paramType.getRawType(); + String typeString = StringUtils.removeAll(paramType.toString(), "capture#\\d+-of\\s+"); + typeString = typeString.replace("(\\?\\s+extends\\s+){2,}", "? extends "); + + boolean isWildCard = typeString.contains("?"); + + // Some specializations need to be done to make sure that the arguments + // are property pulled out and written + + // If its a wild card and it has no boundary other than Object, + // we just use the wild card + if (isWildCard && rawParam.equals(Object.class)) { + bld.append("?"); + continue; + } + + if (asParameter) { + // We handle parameters differently so that it's accepted more "flexibility" + bld.append("? extends "); + } + + // now we recursively add the type parameter, we set `asParameter` to false + // because odds are it will become wrong to keep adding the "extends" boundaries + Package paramPackage = paramType.getRawType().getPackage(); + + getTypeDeclaration(bld, basePackage, paramType, false, + fullyQualified + || ((paramPackage != null && !Objects.equals(basePackage, paramPackage.getName())) + && Objects.equals(paramPackage, raw.getPackage()))); + } + + bld.append(">"); + } + } + + } + + /** + * Gets the name of the class that will be the "assert". + * @param type Type being tested + * @param packageName package this type will reside in + * @return Name for "assert" type + */ + // used to support navigation assertion + // https://github.com/joel-costigliola/assertj-assertions-generator/issues/67 + public static String getAssertType(TypeToken type, String packageName) { + + TypeToken wrapped = type.wrap(); + Class raw = wrapped.getRawType(); + + String typeName = null; + if (isJavaLangType(wrapped)) { + try { + String builtInName = "org.assertj.core.api." + raw.getSimpleName() + "Assert"; + // try to get the class, if it exists, then we know its valid + Class.forName(builtInName); + + typeName = builtInName.substring(0, builtInName.length() - "Assert".length()); + } catch (ClassNotFoundException cfne) { + // it wasn't found, this means the class doesn't exist, so fall through + } + } + + if (typeName == null) { + typeName = type.getRawType().getName(); + } + + return resolveTypeNameInPackage(typeName + "Assert", packageName); + } + + /** + * Gets the name of a type without the package if {@code currentPackage} is the same as + * {@link Class#getPackage() type's package}. + * + * @param type Type to import + * @param currentPackage package context for the string + * @return String Name resolved within the package + */ + public static String resolveTypeNameInPackage(TypeToken type, String currentPackage) { + // we special case java.lang types because they never need a FQN. + if (isJavaLangType(type)) { + return type.getRawType().getSimpleName(); + } + + return resolveTypeNameInPackage(type.getRawType().getName(), currentPackage); + } + + /** + * Gets the name of a type without the package if {@code currentPackage} is the same as + * {@link Class#getPackage() type's package}. + * + * @param type Type to import + * @param currentPackage package context for the string + * @return String Name resolved within the package + */ + public static String resolveTypeNameInPackage(Type type, String currentPackage) { + return resolveTypeNameInPackage(TypeToken.of(type), currentPackage); + } + + /** + * Gets the name of a type without the package if {@code currentPackage} is the same as + * {@link Class#getPackage() type's package}. + * + * @param type Type to import + * @param currentPackage package context for the string + * @return Name resolved within the package + */ + private static String resolveTypeNameInPackage(String type, String currentPackage) { + if (!Strings.isNullOrEmpty(currentPackage) && type.startsWith(currentPackage)) { + return type.substring(currentPackage.length() + 1, type.length()); + } else { + return type; + } + } + + /** + * Gets a type name without any dots in it if they are present -- this is for nested classes + * @param typeName String name of the type + * @return Type without any {@code '.'} characters + */ + public static String getTypeNameWithoutDots(String typeName) { + int indexOfClassName = StringUtils.indexOfAny(typeName, CAPITAL_LETTERS); + final String typeSimpleNameWithOuterClass; + if (indexOfClassName > 0) { + typeSimpleNameWithOuterClass = typeName.substring(indexOfClassName); + } else { + // primitive valueType => no package + typeSimpleNameWithOuterClass = typeName; + } + + return remove(typeSimpleNameWithOuterClass, "."); + } + + /** + * Checks if a type is a boolean type + * @param type Type to check + * @return true iff the type is a boolean. + */ + public static boolean isBoolean(TypeToken type) { + TypeToken unwrapped = type.unwrap(); + return unwrapped.isSubtypeOf(boolean.class); + } } diff --git a/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java b/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java deleted file mode 100644 index 777594c5..00000000 --- a/src/main/java/org/assertj/assertions/generator/util/TypeUtil.java +++ /dev/null @@ -1,320 +0,0 @@ -/** - * 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-2015 the original author or authors. - */ -package org.assertj.assertions.generator.util; - -import com.google.common.base.Strings; -import com.google.common.reflect.TypeToken; -import org.apache.commons.lang3.StringUtils; - -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.commons.lang3.StringUtils.indexOfAny; -import static org.apache.commons.lang3.StringUtils.remove; - -/** - * Includes useful utilities for types. - */ -public class TypeUtil { - - private static final Package JAVA_LANG_PACKAGE = Object.class.getPackage(); - - /** - * Checks if the package, {@code child} is under the package {@code parent}. - * @param child Child package - * @param parent Parent package - * @return True iff the child package is under the parent, false if not or either is {@code null}. - * - * @see #isInnerPackageOf(String, String) String argument equivalent - */ - public static boolean isInnerPackageOf(Package child, Package parent) { - return child != null && parent != null - && child.getName().startsWith(parent.getName()); - } - - /** - * Utility version that allows to pass a string and {@link Package}. - *
- * Delegates to {@link #isInnerPackageOf(String, String)}. - * - * @see #isInnerPackageOf(String, String) - */ - public static boolean isInnerPackageOf(Package child, String parent) { - return child != null && isInnerPackageOf(child.getName(), parent); - } - - /** - * Checks if the package, {@code child} is under the package {@code parent}. - * @param parentPackage Parent package - * @param childPackage Child package - * @return True iff the child package is under the parent, false if not or either is {@code null}. - * - * @see #isInnerPackageOf(String, String) String argument equivalent - */ - public static boolean isInnerPackageOf(String childPackage, String parentPackage) { - checkArgument(!Strings.isNullOrEmpty(childPackage), "childPackage is null or empty"); - checkNotNull(parentPackage, "parentPackage is null or empty"); - - return childPackage.startsWith(parentPackage); - } - - - /** - * Checks if the type passed is a member of {@code java.lang} or is a "built-in" type (e.g. primitive or array). - * @return true if part of java language - */ - public static boolean isJavaLangType(TypeToken type) { - return type.isPrimitive() || type.isArray() || Objects.equals(JAVA_LANG_PACKAGE, type.getRawType().getPackage()); - } - - /** - * Checks if the type passed is a member of {@code java.lang} or is a "built-in" type (e.g. primitive or array). - * @return true if part of java language - * - * @see #isJavaLangType(TypeToken) - */ - public static boolean isJavaLangType(Type type) { - return isJavaLangType(TypeToken.of(type)); - } - - /** - * Generates a "type declaration" that could be used in Java code based on the {@code type} and if it is a parameter, - * it will try to be as "flexible" as possible. - * - * @param type Type to get declaration for - * @param asParameter True if the type is being used as a parameter - * @return String representation of the type - * - * @see #getTypeDeclaration(TypeToken, boolean, boolean) - */ - public static String getTypeDeclaration(TypeToken type, final boolean asParameter, boolean fullyQualified) { - StringBuilder bld = new StringBuilder(); - Class raw = type.getRawType(); - getTypeDeclaration(bld, (raw.getPackage() == null ? null : raw.getPackage().getName()), type, asParameter, fullyQualified); - return bld.toString(); - } - - /** - * Uses the package name as a "local package" and tries to discern whether or not to generate - * fully qualified names. - * @param type Type to get declaration for - * @param packageName local package name - * @param asParameter True if the type is being used as a parameter - * @return String representation of the type - * - * @see #getTypeDeclaration(TypeToken, boolean, boolean) - */ - public static String getTypeDeclarationWithinPackage(TypeToken type, String packageName, final boolean asParameter) { - - boolean reqFQN = !Objects.equals(packageName, JAVA_LANG_PACKAGE.getName()) - && (!type.isPrimitive() && !type.isArray() && !Objects.equals(packageName, type.getRawType().getPackage().getName())); - StringBuilder bld = new StringBuilder(); - getTypeDeclaration(bld, packageName, type, asParameter, reqFQN); - return bld.toString(); - } - - - /** - * helper method for {@code #getTypeDeclarationXXX()} - * @see #getTypeDeclaration(TypeToken, boolean, boolean) - * @see #getTypeDeclarationWithinPackage(TypeToken, String, boolean) - */ - private static void getTypeDeclaration(StringBuilder bld, String basePackage, TypeToken type, boolean asParameter, boolean fullyQualified) { - - Class raw = type.getRawType(); - - // Gotta do some special casing - if (type.isArray()) { - getTypeDeclaration(bld, basePackage, type.getComponentType(), asParameter, fullyQualified); - bld.append("[]"); - } else if (type.isPrimitive()) { - bld.append(raw.toString()); - } else { - // Now we have some types that could be generic, so we have to do more - // to serialize it to the declaration - - if (raw.isMemberClass()) { // inner class - TypeToken outerClass = type.resolveType(raw.getEnclosingClass()); - getTypeDeclaration(bld, basePackage, outerClass, asParameter, fullyQualified); - bld.append("."); - - } else { - // it's a normal class, so just append the package here if needed - if (fullyQualified && !isJavaLangType(type)) { - bld.append(type.getRawType().getPackage().getName()); - bld.append("."); - } - } - - bld.append(raw.getSimpleName()); - - // Now handle generics - if (raw.getTypeParameters().length > 0) { - bld.append("<"); - boolean first = true; - for (TypeVariable tv : raw.getTypeParameters()) { - // only append at the end - if (!first) { - bld.append(','); - } - first = false; - - TypeToken paramType = type.resolveType(tv); - Class rawParam = paramType.getRawType(); - String typeString = StringUtils.removeAll(paramType.toString(), "capture#\\d+-of\\s+"); - typeString = typeString.replace("(\\?\\s+extends\\s+){2,}", "? extends "); - - boolean isWildCard = typeString.contains("?"); - - // Some specializations need to be done to make sure that the arguments - // are property pulled out and written - - // If its a wild card and it has no boundary other than Object, - // we just use the wild card - if (isWildCard && rawParam.equals(Object.class)) { - bld.append("?"); - continue; - } - - if (asParameter) { - // We handle parameters differently so that it's accepted more "flexibility" - bld.append("? extends "); - } - - // now we recursively add the type parameter, we set `asParameter` to false - // because odds are it will become wrong to keep adding the "extends" boundaries - Package paramPackage = paramType.getRawType().getPackage(); - - getTypeDeclaration(bld, basePackage, paramType, false, - fullyQualified - || ((paramPackage != null && !Objects.equals(basePackage, paramPackage.getName())) - && Objects.equals(paramPackage, raw.getPackage()))); - } - - bld.append(">"); - } - } - - } - - /** - * Gets the name of the class that will be the "assert". - * @param type Type being tested - * @param packageName package this type will reside in - * @return Name for "assert" type - */ - // used to support navigation assertion - // https://github.com/joel-costigliola/assertj-assertions-generator/issues/67 - public static String getAssertType(TypeToken type, String packageName) { - - TypeToken wrapped = type.wrap(); - Class raw = wrapped.getRawType(); - - String typeName = null; - if (isJavaLangType(wrapped)) { - try { - String builtInName = "org.assertj.core.api." + raw.getSimpleName() + "Assert"; - // try to get the class, if it exists, then we know its valid - Class.forName(builtInName); - - typeName = builtInName.substring(0, builtInName.length() - "Assert".length()); - } catch (ClassNotFoundException cfne) { - // it wasn't found, this means the class doesn't exist, so fall through - } - } - - if (typeName == null) { - typeName = type.getRawType().getName(); - } - - return resolveTypeNameInPackage(typeName + "Assert", packageName); - } - - /** - * Gets the name of a type without the package if {@code currentPackage} is the same as - * {@link Class#getPackage() type's package}. - * - * @param type Type to import - * @param currentPackage package context for the string - * @return String Name resolved within the package - */ - public static String resolveTypeNameInPackage(TypeToken type, String currentPackage) { - // we special case java.lang types because they never need a FQN. - if (isJavaLangType(type)) { - return type.getRawType().getSimpleName(); - } - - return resolveTypeNameInPackage(type.getRawType().getName(), currentPackage); - } - - /** - * Gets the name of a type without the package if {@code currentPackage} is the same as - * {@link Class#getPackage() type's package}. - * - * @param type Type to import - * @param currentPackage package context for the string - * @return String Name resolved within the package - */ - public static String resolveTypeNameInPackage(Type type, String currentPackage) { - return resolveTypeNameInPackage(TypeToken.of(type), currentPackage); - } - - /** - * Gets the name of a type without the package if {@code currentPackage} is the same as - * {@link Class#getPackage() type's package}. - * - * @param type Type to import - * @param currentPackage package context for the string - * @return Name resolved within the package - */ - private static String resolveTypeNameInPackage(String type, String currentPackage) { - if (!Strings.isNullOrEmpty(currentPackage) && type.startsWith(currentPackage)) { - return type.substring(currentPackage.length() + 1, type.length()); - } else { - return type; - } - } - - private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - /** - * Gets a type name without any dots in it if they are present -- this is for nested classes - * @param typeName String name of the type - * @return Type without any {@code '.'} characters - */ - public static String getTypeNameWithoutDots(String typeName) { - int indexOfClassName = indexOfAny(typeName, CAPITAL_LETTERS); - final String typeSimpleNameWithOuterClass; - if (indexOfClassName > 0) { - typeSimpleNameWithOuterClass = typeName.substring(indexOfClassName); - } else { - // primitive valueType => no package - typeSimpleNameWithOuterClass = typeName; - } - - return remove(typeSimpleNameWithOuterClass, "."); - } - - /** - * Checks if a type is a boolean type - * @param type Type to check - * @return true iff the type is a boolean. - */ - public static boolean isBoolean(TypeToken type) { - TypeToken unwrapped = type.unwrap(); - return unwrapped.isSubtypeOf(boolean.class); - } -} 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 5910a083..74c0a3c6 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 @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -24,7 +24,7 @@ import org.assertj.assertions.generator.data.nba.PlayerAgent; import org.assertj.assertions.generator.description.ClassDescription; import org.assertj.assertions.generator.description.GetterDescription; -import org.assertj.assertions.generator.util.TypeUtil; +import org.assertj.assertions.generator.util.ClassUtil; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.theories.Theories; @@ -202,7 +202,7 @@ public void should_build_class_description_for_iterable_of_Object_type() throws .isTrue(); assertThat(getterDescription.getElementTypeName(WithIterableObjectType.class.getPackage().getName())) .as("getterDesc element type must return correct array type") - .isEqualTo(TypeUtil.getTypeDeclaration(new TypeToken() {}, false, false)); + .isEqualTo(ClassUtil.getTypeDeclaration(new TypeToken() {}, false, false)); assertThat(getterDescription.isArrayType()).as("getterDescription is not an array").isFalse(); } @@ -293,7 +293,7 @@ public void should_only_describe_overriden_getter_once() { } public interface InterfaceWithGetter { - public abstract List getMyList(); + List getMyList(); } class ClassOverridingGetter implements InterfaceWithGetter { 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 26fe11cd..7c8b7f92 100644 --- a/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java +++ b/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java @@ -1,4 +1,4 @@ -/** +/* * 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 * @@ -15,6 +15,7 @@ import com.google.common.base.Function; import com.google.common.collect.Lists; import com.google.common.reflect.TypeToken; +import org.assertj.assertions.generator.AssertionGeneratorTest; import org.assertj.assertions.generator.NestedClassesTest; import org.assertj.assertions.generator.data.*; import org.assertj.assertions.generator.data.lotr.FellowshipOfTheRing; @@ -23,11 +24,14 @@ import org.assertj.assertions.generator.data.lotr.TolkienCharacter; import org.assertj.assertions.generator.data.nba.Player; import org.assertj.assertions.generator.data.nba.PlayerAgent; +import org.assertj.assertions.generator.description.GetterDescriptionTest; +import org.assertj.core.api.BooleanAssert; import org.junit.Test; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.util.*; @@ -268,6 +272,181 @@ public void getClass_on_generic_should_return_Number_class() throws Exception { Class classes = ClassUtil.getClass(method.getGenericReturnType()); assertThat(classes).isEqualTo(Number.class); } + + public static class Inner {} + + @Test + public void resolve_type_name_in_package() throws Exception { + assertThat(ClassUtil.resolveTypeNameInPackage(String.class, String.class.getPackage().getName())) + .as("java lang type has simple name with package") + .isEqualTo(String.class.getSimpleName()); + assertThat(ClassUtil.resolveTypeNameInPackage(String.class, null)) + .as("java lang type has simple name without package") + .isEqualTo(String.class.getSimpleName()); + + assertThat(ClassUtil.resolveTypeNameInPackage(ClassUtilTest.class, null)) + .as("normal type has FQN without package") + .isEqualTo(ClassUtilTest.class.getName()); + assertThat(ClassUtil.resolveTypeNameInPackage(ClassUtilTest.class, ClassUtilTest.class.getPackage().getName())) + .as("normal type does not has FQN with package") + .isEqualTo(ClassUtilTest.class.getSimpleName()); + assertThat(ClassUtil.resolveTypeNameInPackage(ClassUtilTest.class, String.class.getPackage().getName())) + .as("normal type does not have FQN with other package") + .isEqualTo(ClassUtilTest.class.getName()); + + assertThat(ClassUtil.resolveTypeNameInPackage(Inner.class, null)) + .as("inner type has FQN without package") + .isEqualTo(Inner.class.getName()); + assertThat(ClassUtil.resolveTypeNameInPackage(Inner.class, Inner.class.getPackage().getName())) + .as("inner type does not have FQN with package") + .isEqualTo(String.format("%s$%s", ClassUtilTest.class.getSimpleName(), Inner.class.getSimpleName())); + } + + + @Test + public void java_lang_types_should_work_with_isJavaLangType() throws Exception { + assertThat(ClassUtil.isJavaLangType(Object.class)).isTrue(); + assertThat(ClassUtil.isJavaLangType(boolean.class)).isTrue(); + assertThat(ClassUtil.isJavaLangType(Boolean.class)).isTrue(); + + // wrong + assertThat(ClassUtil.isJavaLangType(ClassUtilTest.class)).isFalse(); + } + + @Test + public void can_properly_compute_Assert_types() throws Exception { + TypeToken thisType = TypeToken.of(ClassUtilTest.class); + + assertThat(ClassUtil.getAssertType(thisType, thisType.getRawType().getPackage().getName())) + .as("resolves non-built-in type correctly") + .isEqualTo("ClassUtilTestAssert"); + + TypeToken primitive = TypeToken.of(boolean.class); + assertThat(ClassUtil.getAssertType(primitive, thisType.getRawType().getPackage().getName())) + .as("resolves primitive correctly") + .isEqualTo(BooleanAssert.class.getName()); + + TypeToken wrapper = TypeToken.of(Boolean.class); + assertThat(ClassUtil.getAssertType(wrapper, thisType.getRawType().getPackage().getName())) + .as("resolves primitive wrapper correctly") + .isEqualTo(BooleanAssert.class.getName()); + + assertThat(ClassUtil.getAssertType(wrapper, BooleanAssert.class.getPackage().getName())) + .as("resolves package correctly for built-in package") + .isEqualTo(BooleanAssert.class.getSimpleName()); + } + + @Test + public void properly_check_if_types_are_boolean() throws Exception { + TypeToken wrapper = new TypeToken(getClass()) {}; + TypeToken primitive = TypeToken.of(boolean.class); + TypeToken neither = TypeToken.of(ClassUtilTest.class); + + assertThat(ClassUtil.isBoolean(wrapper)).as("for wrapper").isTrue(); + assertThat(ClassUtil.isBoolean(primitive)).as("for primitive").isTrue(); + assertThat(ClassUtil.isBoolean(neither)).as("for non-boolean").isFalse(); + } + + @Test + public void should_check_that_nested_packages_work() throws Exception { + + assertThat(ClassUtil.isInnerPackageOf(ClassUtilTest.class.getPackage(), + AssertionGeneratorTest.class.getPackage())) + .as("from 'super' package") + .isTrue(); + + assertThat(ClassUtil.isInnerPackageOf(ClassUtilTest.class.getPackage(), + ClassUtilTest.class.getPackage())) + .as("same package") + .isTrue(); + + assertThat(ClassUtil.isInnerPackageOf(ClassUtilTest.class.getPackage(), + GetterDescriptionTest.class.getPackage())) + .as("sibling package") + .isFalse(); + + } + + @SuppressWarnings("unused") + static class Foo { + List listOfT; + List> listOfFooString; + List[]> listOfFooIntArr; + List[]> listOfFooIntArrArrArr; + Class clazz; + Class> clazzFoo; + } + + @Test + public void create_generic_type_declaration() throws Exception { + TypeToken> fooInteger = new TypeToken>(getClass()) {}; + String result = ClassUtil.getTypeDeclaration(fooInteger, false, true); + String expected = String.format("%s.%s.%s", ClassUtilTest.class.getPackage().getName(), ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // nested! + TypeToken>> fooFooInteger = new TypeToken>>(getClass()){}; + result = ClassUtil.getTypeDeclaration(fooFooInteger, false, false); + expected = String.format("%s.%s<%s.%s>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName(), + ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // check getting the field's type + Field listOfTField = Foo.class.getDeclaredField("listOfT"); + result = ClassUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfTField.getGenericType()), false, false); + expected = String.format("List<%s.%s>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + result = ClassUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfTField.getGenericType()), true, false); + expected = String.format("List>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // List of non-T type + Field listOfFooStringField = Foo.class.getDeclaredField("listOfFooString"); + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooStringField.getGenericType()), false, false); + expected = String.format("List<%s.%s>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooStringField.getGenericType()), true, false); + expected = String.format("List>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // List of Foo[] + + Field listOfFooIntArr = Foo.class.getDeclaredField("listOfFooIntArr"); + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooIntArr.getGenericType()), false, false); + expected = String.format("List<%s.%s[]>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + // List of Foo[] + Field listOfFooIntArrArrArr = Foo.class.getDeclaredField("listOfFooIntArrArrArr"); + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooIntArrArrArr.getGenericType()), false, false); + expected = String.format("List<%s.%s[]>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + } + + + @Test + public void create_wildcard_version() throws Exception { + TypeToken> fooInteger = new TypeToken>(getClass()) {}; + Field clazz = Foo.class.getDeclaredField("clazz"); + String result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(clazz.getGenericType()), false, true); + String expected = "Class"; + assertThat(result).isEqualTo(expected); + + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(clazz.getGenericType()), true, false); + assertThat(result).isEqualTo(expected); + + Field clazzFoo = Foo.class.getDeclaredField("clazzFoo"); + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(clazzFoo.getGenericType()), true, false); + expected = String.format("Class>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + + result = ClassUtil.getTypeDeclaration(fooInteger.resolveType(clazzFoo.getGenericType()), false, false); + expected = String.format("Class<%s.%s>", ClassUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); + assertThat(result).isEqualTo(expected); + } + private static class Generic { @SuppressWarnings("unused") diff --git a/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java b/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java deleted file mode 100644 index 7a8daf4a..00000000 --- a/src/test/java/org/assertj/assertions/generator/util/TypeUtilTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/** - * 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-2015 the original author or authors. - */ -package org.assertj.assertions.generator.util; - -import com.google.common.reflect.TypeToken; -import org.assertj.assertions.generator.AssertionGeneratorTest; -import org.assertj.assertions.generator.description.GetterDescriptionTest; -import org.assertj.core.api.BooleanAssert; -import org.junit.Test; - -import java.lang.reflect.Field; -import java.util.List; - -import static org.assertj.core.api.Java6Assertions.assertThat; - -/** - * Describes tests for the {@link TypeUtil} class - */ -public class TypeUtilTest { - - public static class Inner {} - - @Test - public void resolveTypeNameInPackage() throws Exception { - assertThat(TypeUtil.resolveTypeNameInPackage(String.class, String.class.getPackage().getName())) - .as("java lang type has simple name with package") - .isEqualTo(String.class.getSimpleName()); - assertThat(TypeUtil.resolveTypeNameInPackage(String.class, null)) - .as("java lang type has simple name without package") - .isEqualTo(String.class.getSimpleName()); - - - assertThat(TypeUtil.resolveTypeNameInPackage(TypeUtilTest.class, null)) - .as("normal type has FQN without package") - .isEqualTo(TypeUtilTest.class.getName()); - assertThat(TypeUtil.resolveTypeNameInPackage(TypeUtilTest.class, TypeUtilTest.class.getPackage().getName())) - .as("normal type does not has FQN with package") - .isEqualTo(TypeUtilTest.class.getSimpleName()); - assertThat(TypeUtil.resolveTypeNameInPackage(TypeUtilTest.class, String.class.getPackage().getName())) - .as("normal type does not have FQN with other package") - .isEqualTo(TypeUtilTest.class.getName()); - - - assertThat(TypeUtil.resolveTypeNameInPackage(Inner.class, null)) - .as("inner type has FQN without package") - .isEqualTo(Inner.class.getName()); - assertThat(TypeUtil.resolveTypeNameInPackage(Inner.class, Inner.class.getPackage().getName())) - .as("inner type does not have FQN with package") - .isEqualTo(String.format("%s$%s", TypeUtilTest.class.getSimpleName(), Inner.class.getSimpleName())); - } - - - @Test - public void isJavaLangType() throws Exception { - assertThat(TypeUtil.isJavaLangType(Object.class)).isTrue(); - assertThat(TypeUtil.isJavaLangType(boolean.class)).isTrue(); - assertThat(TypeUtil.isJavaLangType(Boolean.class)).isTrue(); - - // wrong - assertThat(TypeUtil.isJavaLangType(TypeUtilTest.class)).isFalse(); - } - - @Test - public void getAssertType() throws Exception { - TypeToken thisType = TypeToken.of(TypeUtilTest.class); - - assertThat(TypeUtil.getAssertType(thisType, thisType.getRawType().getPackage().getName())) - .as("resolves non-built-in type correctly") - .isEqualTo("TypeUtilTestAssert"); - - TypeToken primitive = TypeToken.of(boolean.class); - assertThat(TypeUtil.getAssertType(primitive, thisType.getRawType().getPackage().getName())) - .as("resolves primitive correctly") - .isEqualTo(BooleanAssert.class.getName()); - - TypeToken wrapper = TypeToken.of(Boolean.class); - assertThat(TypeUtil.getAssertType(wrapper, thisType.getRawType().getPackage().getName())) - .as("resolves primitive wrapper correctly") - .isEqualTo(BooleanAssert.class.getName()); - - assertThat(TypeUtil.getAssertType(wrapper, BooleanAssert.class.getPackage().getName())) - .as("resolves package correctly for built-in package") - .isEqualTo(BooleanAssert.class.getSimpleName()); - } - - @Test - public void getTypeNameWithoutDots() throws Exception { - } - - @Test - public void isBoolean() throws Exception { - TypeToken wrapper = new TypeToken(getClass()) {}; - TypeToken primitive = TypeToken.of(boolean.class); - TypeToken neither = TypeToken.of(TypeUtilTest.class); - - assertThat(TypeUtil.isBoolean(wrapper)).as("for wrapper").isTrue(); - assertThat(TypeUtil.isBoolean(primitive)).as("for primitive").isTrue(); - assertThat(TypeUtil.isBoolean(neither)).as("for non-boolean").isFalse(); - } - - @Test - public void isInnerPackageOf() throws Exception { - - assertThat(TypeUtil.isInnerPackageOf(TypeUtilTest.class.getPackage(), - AssertionGeneratorTest.class.getPackage())) - .as("from 'super' package") - .isTrue(); - - assertThat(TypeUtil.isInnerPackageOf(TypeUtilTest.class.getPackage(), - TypeUtilTest.class.getPackage())) - .as("same package") - .isTrue(); - - assertThat(TypeUtil.isInnerPackageOf(TypeUtilTest.class.getPackage(), - GetterDescriptionTest.class.getPackage())) - .as("sibling package") - .isFalse(); - - } - - @SuppressWarnings("unused") - static class Foo { - List listOfT; - List> listOfFooString; - List[]> listOfFooIntArr; - List[]> listOfFooIntArrArrArr; - Class clazz; - Class> clazzFoo; - } - - @Test - public void create_generic_type_declaration() throws Exception { - TypeToken> fooInteger = new TypeToken>(getClass()) {}; - String result = TypeUtil.getTypeDeclaration(fooInteger, false, true); - String expected = String.format("%s.%s.%s", TypeUtilTest.class.getPackage().getName(), TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - // nested! - TypeToken>> fooFooInteger = new TypeToken>>(getClass()){}; - result = TypeUtil.getTypeDeclaration(fooFooInteger, false, false); - expected = String.format("%s.%s<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName(), - TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - // check getting the field's type - Field listOfTField = Foo.class.getDeclaredField("listOfT"); - result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfTField.getGenericType()), false, false); - expected = String.format("List<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - result = TypeUtil.getTypeDeclaration(fooFooInteger.resolveType(listOfTField.getGenericType()), true, false); - expected = String.format("List>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - // List of non-T type - Field listOfFooStringField = Foo.class.getDeclaredField("listOfFooString"); - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooStringField.getGenericType()), false, false); - expected = String.format("List<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooStringField.getGenericType()), true, false); - expected = String.format("List>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - // List of Foo[] - - Field listOfFooIntArr = Foo.class.getDeclaredField("listOfFooIntArr"); - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooIntArr.getGenericType()), false, false); - expected = String.format("List<%s.%s[]>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - // List of Foo[] - Field listOfFooIntArrArrArr = Foo.class.getDeclaredField("listOfFooIntArrArrArr"); - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(listOfFooIntArrArrArr.getGenericType()), false, false); - expected = String.format("List<%s.%s[]>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - } - - - @Test - public void create_wildcard_version() throws Exception { - TypeToken> fooInteger = new TypeToken>(getClass()) {}; - Field clazz = Foo.class.getDeclaredField("clazz"); - String result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazz.getGenericType()), false, true); - String expected = "Class"; - assertThat(result).isEqualTo(expected); - - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazz.getGenericType()), true, false); - assertThat(result).isEqualTo(expected); - - Field clazzFoo = Foo.class.getDeclaredField("clazzFoo"); - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazzFoo.getGenericType()), true, false); - expected = String.format("Class>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - - result = TypeUtil.getTypeDeclaration(fooInteger.resolveType(clazzFoo.getGenericType()), false, false); - expected = String.format("Class<%s.%s>", TypeUtilTest.class.getSimpleName(), Foo.class.getSimpleName()); - assertThat(result).isEqualTo(expected); - } - - -} \ No newline at end of file From f17073be3213a97b788eeb1ff2ea8022d64d46e2 Mon Sep 17 00:00:00 2001 From: Kevin Brightwell Date: Fri, 26 May 2017 13:29:09 -0400 Subject: [PATCH 4/5] Adds support for Compile Tests (#37) I ended up closing #37 because I was worried I generated incorrect code, thus I added the suggestion in #37. Additionally, I found bugs in generation and fixed them. I refactored the generation tests to use a common junit "Rule" called `GenerationPathHandler` that handles using a temporary file per test case so there is no worry of collusion of generated files. The Rule handles making all paths relative to the path generated and deletes the folder IFF the tests pass, otherwise the folder is kept and the path is printed to the error console. --- pom.xml | 20 +- .../generator/BaseAssertionGenerator.java | 9 +- .../description/ClassDescription.java | 2 +- .../description/DataDescription.java | 2 +- .../description/FieldDescription.java | 2 +- .../description/GetterDescription.java | 2 +- .../assertions/generator/util/ClassUtil.java | 2 +- ...ssertionGeneratorOverrideTemplateTest.java | 19 +- .../generator/AssertionGeneratorTest.java | 120 +++++----- .../AssertionsEntryPointGeneratorTest.java | 17 +- .../generator/GenerationPathHandler.java | 211 ++++++++++++++++++ .../ClassToClassDescriptionConverterTest.java | 2 +- .../generator/util/ClassUtilTest.java | 2 +- .../resources/BooleanPredicates.expected.txt | 24 +- 14 files changed, 325 insertions(+), 109 deletions(-) create mode 100644 src/test/java/org/assertj/assertions/generator/GenerationPathHandler.java diff --git a/pom.xml b/pom.xml index 3d275874..53d60b85 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,21 @@ 4.11 test + + + commons-io + commons-io + 2.5 + test + + + + + com.google.testing.compile + compile-testing + 0.11 + test + @@ -106,7 +121,7 @@
- + org.jacoco jacoco-maven-plugin @@ -122,6 +137,9 @@ maven-surefire-plugin ${argLine} + + false diff --git a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java index db0bd4e2..2bf76d75 100644 --- a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java @@ -1,4 +1,4 @@ -/* +/** * 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 * @@ -24,6 +24,7 @@ import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Method; +import java.nio.file.Paths; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -71,7 +72,7 @@ public class BaseAssertionGenerator implements AssertionGenerator, AssertionsEnt private static final String LINE_SEPARATOR = "\n"; // assertions classes are generated in their package directory starting from targetBaseDirectory. // ex : com.nba.Player -> targetBaseDirectory/com/nba/PlayerAssert.java - private String targetBaseDirectory = "."; + private File targetBaseDirectory = Paths.get(".").toFile(); private TemplateRegistry templateRegistry;// the pattern to search for /** @@ -113,7 +114,7 @@ public BaseAssertionGenerator(String templatesDirectory) throws IOException { templateRegistry = DefaultTemplateRegistryProducer.create(templatesDirectory); } - public void setDirectoryWhereAssertionFilesAreGenerated(String targetBaseDirectory) { + public void setDirectoryWhereAssertionFilesAreGenerated(File targetBaseDirectory) { this.targetBaseDirectory = targetBaseDirectory; } @@ -483,7 +484,7 @@ private String assertionContentForField(FieldDescription field, ClassDescription // replace ${Property} and ${property} by field name (starting with uppercase/lowercase) if (field.isPredicate()) { - assertionContent = assertionContent.replace("actual." + PREDICATE + "()", "actual." + field.getName()); + assertionContent = assertionContent.replace("actual." + PREDICATE + "()", "actual." + field.getOriginalMember().getName()); assertionContent = assertionContent.replace(PREDICATE_FOR_JAVADOC, field.getPredicateForJavadoc()); assertionContent = assertionContent.replace(NEGATIVE_PREDICATE_FOR_JAVADOC, diff --git a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java index 3404d2a0..ec3b5be7 100644 --- a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java index 999b5b84..80cfa084 100644 --- a/src/main/java/org/assertj/assertions/generator/description/DataDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/DataDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java index ab0aa93e..bd09b8c8 100644 --- a/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/FieldDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java index 46b60b69..764d0be8 100644 --- a/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/GetterDescription.java @@ -1,4 +1,4 @@ -/* +/** * 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 * 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 f601541a..f1f45625 100644 --- a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorOverrideTemplateTest.java b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorOverrideTemplateTest.java index a61318d5..c19a4e71 100644 --- a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorOverrideTemplateTest.java +++ b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorOverrideTemplateTest.java @@ -12,24 +12,27 @@ */ package org.assertj.assertions.generator; -import static org.assertj.assertions.generator.AssertionGeneratorTest.assertGeneratedAssertClass; - -import java.io.File; -import java.io.IOException; - import org.assertj.assertions.generator.data.cars.Car; import org.assertj.assertions.generator.description.converter.ClassToClassDescriptionConverter; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; + public class AssertionGeneratorOverrideTemplateTest { private BaseAssertionGenerator assertionGenerator; private ClassToClassDescriptionConverter converter; + @Rule + public final GenerationPathHandler genHandle = new GenerationPathHandler(AssertionGeneratorOverrideTemplateTest.class, + Paths.get("src/test/resources")); + @Before public void before() throws IOException { - assertionGenerator = new BaseAssertionGenerator(); - assertionGenerator.setDirectoryWhereAssertionFilesAreGenerated("target"); + assertionGenerator = genHandle.buildAssertionGenerator(); converter = new ClassToClassDescriptionConverter(); } @@ -55,6 +58,6 @@ public void should_generate_assertion_with_custom_template() throws IOException "custom_has_assertion_template_for_whole_number.txt"))); assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Car.class)); - assertGeneratedAssertClass(Car.class, "CarAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(Car.class, "CarAssert.expected.txt", true); } } diff --git a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java index 52c43a55..6555a42e 100644 --- a/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java +++ b/src/test/java/org/assertj/assertions/generator/AssertionGeneratorTest.java @@ -20,6 +20,7 @@ import org.assertj.assertions.generator.description.converter.AnnotationConfiguration; import org.assertj.assertions.generator.description.converter.ClassToClassDescriptionConverter; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; @@ -29,18 +30,13 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Paths; import java.sql.SQLException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; -import static com.google.common.collect.Sets.newHashSet; import static java.lang.reflect.Modifier.isPublic; import static java.nio.charset.Charset.defaultCharset; import static org.apache.commons.lang3.StringUtils.replace; -import static org.assertj.assertions.generator.BaseAssertionGenerator.ABSTRACT_ASSERT_CLASS_PREFIX; -import static org.assertj.assertions.generator.BaseAssertionGenerator.ASSERT_CLASS_FILE_SUFFIX; import static org.assertj.assertions.generator.util.ClassUtil.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.contentOf; @@ -48,104 +44,113 @@ @RunWith(Theories.class) public class AssertionGeneratorTest implements NestedClassesTest, BeanWithExceptionsTest { private static final String LINE_SEPARATOR = "\n"; - private static final String TARGET_DIRECTORY = "target"; - private static final File RESOURCES_DIRECTORY = new File("src/test/resources"); private static final Logger logger = LoggerFactory.getLogger(AssertionGeneratorTest.class); private ClassToClassDescriptionConverter converter; private AssertionGenerator assertionGenerator; private static final Set> allClasses = - newHashSet(Arrays.>asList(TypeToken.of(Movie.class), TypeToken.of(ArtWork.class))); + new HashSet<>(Arrays.>asList(TypeToken.of(Movie.class), TypeToken.of(ArtWork.class))); + + @Rule + public final GenerationPathHandler genHandle = new GenerationPathHandler(AssertionGeneratorTest.class, Paths.get("src/test/resources")); @Before public void beforeEachTest() throws IOException { converter = new ClassToClassDescriptionConverter(); - assertionGenerator = buildAssertionGenerator(); - } - - public AssertionGenerator buildAssertionGenerator() throws IOException { - BaseAssertionGenerator assertionGenerator = new BaseAssertionGenerator(); - assertionGenerator.setDirectoryWhereAssertionFilesAreGenerated(TARGET_DIRECTORY); - return assertionGenerator; + assertionGenerator = genHandle.buildAssertionGenerator(); } @Test public void should_generate_assertion_for_player_class() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Player.class)); - assertGeneratedAssertClass(Player.class, "PlayerAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(Player.class, "PlayerAssert.expected.txt", true); } @Test public void should_generate_assertion_for_interface() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(PlayerAgent.class)); - assertGeneratedAssertClass(PlayerAgent.class, "PlayerAgentAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(PlayerAgent.class, "PlayerAgentAssert.expected.txt", true); } @Test public void should_generate_assertion_for_class_with_public_fields() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Team.class)); - assertGeneratedAssertClass(Team.class, "TeamAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(Team.class, "TeamAssert.expected.txt", true); } @Test public void should_generate_assertion_for_class_with_properties_that_clash_with_fields() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(FieldPropertyClash.class)); - assertGeneratedAssertClass(FieldPropertyClash.class, "FieldPropertyClash.expected.txt"); + genHandle.assertGeneratedAssertClass(FieldPropertyClash.class, "FieldPropertyClash.expected.txt", true); } @Test public void should_generate_assertion_for_class_with_properties_that_clash_with_keywords() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Keywords.class)); - assertGeneratedAssertClass(Keywords.class, "Keywords.expected.txt"); + genHandle.assertGeneratedAssertClass(Keywords.class, "Keywords.expected.txt", true); } @Test public void should_generate_assertion_for_class_with_predicates() throws Exception { ClassDescription classDescription = converter.convertToClassDescription(BooleanPredicates.class); assertionGenerator.generateCustomAssertionFor(classDescription); - assertGeneratedAssertClass(BooleanPredicates.class, "BooleanPredicates.expected.txt"); + genHandle.assertGeneratedAssertClass(BooleanPredicates.class, "BooleanPredicates.expected.txt", true); } @Test public void should_generate_assertion_for_class_with_primitives() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Primitives.class)); - assertGeneratedAssertClass(Primitives.class, "PrimitivesAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(Primitives.class, "PrimitivesAssert.expected.txt", true); } @Test public void should_generate_assertion_for_class_with_interference_primitives() throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(InterferencePrimitives.class)); - assertGeneratedAssertClass(InterferencePrimitives.class, "InterferencePrimitivesAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(InterferencePrimitives.class, "InterferencePrimitivesAssert.expected.txt", true); } @Test public void should_generate_flat_assertion_for_movie_class() throws Exception { - assertThat(abstractFileGeneratedFor(Movie.class).delete()).isTrue(); assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(Movie.class)); - assertGeneratedAssertClass(Movie.class, "MovieAssert.flat.expected.txt"); - assertThat(abstractFileGeneratedFor(Movie.class)).doesNotExist(); + genHandle.assertGeneratedAssertClass(Movie.class, "MovieAssert.flat.expected.txt", true); + assertThat(genHandle.abstractFileGeneratedFor(Movie.class)).doesNotExist(); } @Test public void should_generate_hierarchical_assertion_for_movie_class() throws Exception { - assertionGenerator.generateHierarchicalCustomAssertionFor(converter.convertToClassDescription(Movie.class), - allClasses); - assertGeneratedAssertClass(Movie.class, "MovieAssert.expected.txt"); - assertAbstractGeneratedAssertClass(Movie.class, "AbstractMovieAssert.expected.txt"); + List generated = new ArrayList<>(4); + + File[] movieFiles = assertionGenerator.generateHierarchicalCustomAssertionFor(converter.convertToClassDescription(Movie.class), + allClasses); + generated.addAll(Arrays.asList(movieFiles)); + + genHandle.assertGeneratedAssertClass(Movie.class, "MovieAssert.expected.txt", false); + genHandle.assertAbstractGeneratedAssertClass(Movie.class, "AbstractMovieAssert.expected.txt"); + + // These should also be generated! + File[] artWorkFiles = assertionGenerator.generateHierarchicalCustomAssertionFor(converter.convertToClassDescription(ArtWork.class), + allClasses); + generated.addAll(Arrays.asList(artWorkFiles)); + genHandle.assertGeneratedAssertClass(ArtWork.class, "ArtWorkAssert.expected.txt", false); + genHandle.assertAbstractGeneratedAssertClass(ArtWork.class, "AbstractArtWorkAssert.expected.txt"); + + // compile them + genHandle.compileGeneratedFiles(generated); } @Test public void should_generate_hierarchical_assertion_for_artwork_class() throws Exception { assertionGenerator.generateHierarchicalCustomAssertionFor(converter.convertToClassDescription(ArtWork.class), - allClasses); - assertGeneratedAssertClass(ArtWork.class, "ArtWorkAssert.expected.txt"); - assertAbstractGeneratedAssertClass(ArtWork.class, "AbstractArtWorkAssert.expected.txt"); + allClasses); + + genHandle.assertAbstractGeneratedAssertClass(ArtWork.class, "AbstractArtWorkAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(ArtWork.class, "ArtWorkAssert.expected.txt", true); } @Theory public void should_generate_assertion_for_nested_class(NestedClass nestedClass) throws Exception { Class clazz = nestedClass.getNestedClass(); assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(clazz)); - assertThat(fileGeneratedFor(clazz)).hasContent(expectedContentFromTemplate(clazz, + assertThat(genHandle.fileGeneratedFor(clazz)).hasContent(expectedContentFromTemplate(clazz, "NestedClassAssert.template.expected.txt")); } @@ -153,7 +158,7 @@ public void should_generate_assertion_for_nested_class(NestedClass nestedClass) public void should_generate_hierarchical_assertion_for_nested_class(NestedClass nestedClass) throws Exception { Class clazz = nestedClass.getNestedClass(); assertionGenerator.generateHierarchicalCustomAssertionFor(converter.convertToClassDescription(clazz), null); - assertThat(fileGeneratedFor(clazz)).hasContent(expectedContentFromTemplate(clazz, + assertThat(genHandle.fileGeneratedFor(clazz)).hasContent(expectedContentFromTemplate(clazz, "NestedClassAssert.hierarchical.template.expected.txt")); } @@ -161,7 +166,7 @@ public void should_generate_hierarchical_assertion_for_nested_class(NestedClass public void should_generate_assertion_for_property_with_exception(TypeToken beanType) throws Exception { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(beanType)); Class clazz = beanType.getRawType(); - String expectedContent = contentOf(new File(RESOURCES_DIRECTORY, "BeanWithOneException.expected.txt"), defaultCharset()); + String expectedContent = contentOf(genHandle.getResourcesDir().resolve("BeanWithOneException.expected.txt").toFile(), defaultCharset()); if (!BEAN_WITH_ONE_EXCEPTION.equals(beanType)) { expectedContent = expectedContent.replace(BEAN_WITH_ONE_EXCEPTION.getRawType().getSimpleName(), clazz.getSimpleName()); expectedContent = expectedContent.replace(" throws java.io.IOException ", @@ -178,7 +183,7 @@ public void should_generate_assertion_for_property_with_exception(TypeToken b expectedContent = expectedContent.replace(throwsClause, replacement); } } - assertThat(fileGeneratedFor(clazz)).hasContent(expectedContent); + assertThat(genHandle.fileGeneratedFor(clazz)).hasContent(expectedContent); } @Test @@ -216,63 +221,42 @@ public void should_generate_assertion_for_classes_in_package_using_provided_clas public void should_generate_assertion_for_classes_using_type_with_same_name() throws IOException { Class clazz = ClassUsingDifferentClassesWithSameName.class; assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(clazz)); - assertGeneratedAssertClass(ClassUsingDifferentClassesWithSameName.class, - "ClassUsingDifferentClassesWithSameName.expected.txt"); + genHandle.assertGeneratedAssertClass(ClassUsingDifferentClassesWithSameName.class, + "ClassUsingDifferentClassesWithSameName.expected.txt", true); } @Test public void should_generate_assertion_for_annotated_methods() throws IOException { converter = new ClassToClassDescriptionConverter(new AnnotationConfiguration(GenerateAssertion.class)); assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(AnnotatedClass.class)); - assertGeneratedAssertClass(AnnotatedClass.class, "AnnotatedClassAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(AnnotatedClass.class, "AnnotatedClassAssert.expected.txt", true); } @Test public void should_generate_assertion_for_methods_annotated_with_GenerateAssertion_by_default() throws IOException { assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(AnnotatedClass.class)); - assertGeneratedAssertClass(AnnotatedClass.class, "AnnotatedClassAssert.expected.txt"); + genHandle.assertGeneratedAssertClass(AnnotatedClass.class, "AnnotatedClassAssert.expected.txt", true); } @Test public void should_generate_assertion_for_annotated_class() throws IOException { converter = new ClassToClassDescriptionConverter(new AnnotationConfiguration(AutoValue.class)); assertionGenerator.generateCustomAssertionFor(converter.convertToClassDescription(AutoValueAnnotatedClass.class)); - assertGeneratedAssertClass(AutoValueAnnotatedClass.class, "AutoValueAnnotatedClassAssert.expected.txt"); - } - - static void assertGeneratedAssertClass(Class clazz, String expectedAssertFile) { - File expectedFile = new File(RESOURCES_DIRECTORY, expectedAssertFile).getAbsoluteFile(); - assertThat(fileGeneratedFor(clazz)).hasSameContentAs(expectedFile); + genHandle.assertGeneratedAssertClass(AutoValueAnnotatedClass.class, "AutoValueAnnotatedClassAssert.expected.txt", true); } - private static void assertAbstractGeneratedAssertClass(Class clazz, String expectedAssertFile) { - File expectedFile = new File(RESOURCES_DIRECTORY, expectedAssertFile).getAbsoluteFile(); - assertThat(abstractFileGeneratedFor(clazz)).hasSameContentAs(expectedFile); - } - private static String expectedContentFromTemplate(Class clazz, String fileTemplate) throws IOException { - String template = contentOf(new File(RESOURCES_DIRECTORY, fileTemplate), defaultCharset()); + private String expectedContentFromTemplate(Class clazz, String fileTemplate) throws IOException { + String template = contentOf(genHandle.getResourcesDir().resolve(fileTemplate).toFile(), defaultCharset()); String content = replace(template, "${nestedClass}Assert", getSimpleNameWithOuterClassNotSeparatedByDots(clazz) + "Assert"); content = replace(content, "${nestedClass}", getSimpleNameWithOuterClass(clazz)); return content; } - private static File fileGeneratedFor(Class clazz) { - String dirName = TARGET_DIRECTORY + File.separatorChar - + clazz.getPackage().getName().replace('.', File.separatorChar); - String generatedFileName = getSimpleNameWithOuterClassNotSeparatedByDots(clazz) + ASSERT_CLASS_FILE_SUFFIX; - return new File(dirName, generatedFileName); - } - private static File abstractFileGeneratedFor(Class clazz) { - String dirName = TARGET_DIRECTORY + File.separatorChar - + clazz.getPackage().getName().replace('.', File.separatorChar); - String generatedFileName = ABSTRACT_ASSERT_CLASS_PREFIX + getSimpleNameWithOuterClassNotSeparatedByDots(clazz) - + ASSERT_CLASS_FILE_SUFFIX; - return new File(dirName, generatedFileName); - } + @SuppressWarnings("WeakerAccess") class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); diff --git a/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java b/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java index 96d8a894..767fd886 100644 --- a/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java +++ b/src/test/java/org/assertj/assertions/generator/AssertionsEntryPointGeneratorTest.java @@ -25,10 +25,12 @@ import org.assertj.assertions.generator.description.ClassDescription; import org.assertj.assertions.generator.description.converter.ClassToClassDescriptionConverter; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import java.io.File; import java.io.IOException; +import java.nio.file.Paths; import java.util.LinkedHashSet; import java.util.Set; @@ -38,12 +40,15 @@ import static org.assertj.core.api.Assertions.contentOf; public class AssertionsEntryPointGeneratorTest { - private static final String TARGET_DIRECTORY = "target"; private BaseAssertionGenerator generator; + @Rule + public final GenerationPathHandler genHandle = new GenerationPathHandler(AssertionsEntryPointGeneratorTest.class, + Paths.get("src/test/resources")); + @Before public void beforeEachTest() throws IOException { - generator = buildAssertionGenerator(); + generator = genHandle.buildAssertionGenerator(); } @Test @@ -87,7 +92,7 @@ public void should_generate_assertion_entry_point_class_file_with_custom_package String expectedContent = readExpectedContentFromFile("AssertionsWithCustomPackage.expected.txt"); assertThat(assertionsEntryPointFile).as("check entry point class content") .hasContent(expectedContent) - .hasParent("target/my/custom/package"); + .hasParent(genHandle.getRoot().toPath().resolve("my/custom/package").toFile()); } @Test @@ -267,12 +272,6 @@ private Set getClassDescriptionsOf(Class... classes) { return classDescriptionSet; } - private BaseAssertionGenerator buildAssertionGenerator() throws IOException { - BaseAssertionGenerator assertionGenerator = new BaseAssertionGenerator(); - assertionGenerator.setDirectoryWhereAssertionFilesAreGenerated(TARGET_DIRECTORY); - return assertionGenerator; - } - private String readExpectedContentFromFile(String fileWithExpectedContent) { return contentOf(new File("src/test/resources", fileWithExpectedContent)); } diff --git a/src/test/java/org/assertj/assertions/generator/GenerationPathHandler.java b/src/test/java/org/assertj/assertions/generator/GenerationPathHandler.java new file mode 100644 index 00000000..1291ae37 --- /dev/null +++ b/src/test/java/org/assertj/assertions/generator/GenerationPathHandler.java @@ -0,0 +1,211 @@ +/** + * 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-2015 the original author or authors. + */ +package org.assertj.assertions.generator; + +import com.google.common.base.Joiner; +import com.google.testing.compile.Compilation; +import com.google.testing.compile.CompilationSubject; +import com.google.testing.compile.Compiler; +import com.google.testing.compile.JavaFileObjects; +import org.assertj.core.api.Assertions; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import javax.tools.JavaFileObject; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +import static org.assertj.assertions.generator.BaseAssertionGenerator.ABSTRACT_ASSERT_CLASS_PREFIX; +import static org.assertj.assertions.generator.BaseAssertionGenerator.ASSERT_CLASS_FILE_SUFFIX; +import static org.assertj.assertions.generator.util.ClassUtil.getSimpleNameWithOuterClassNotSeparatedByDots; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test {@link org.junit.Rule} used to generate temporary folders per test case so there is no concern of + * tests interacting with each other. This utilizes the built-in {@link TemporaryFolder} to accomplish this and + * contains generator specific methods. + */ +public class GenerationPathHandler extends TemporaryFolder { + + + public static final Path DEFAULT_GENERATION_ROOT = Paths.get("target/generated-test-output"); + + private final Compiler compiler; + private Path resourcesDir; + + public GenerationPathHandler(final Class owningClass, Path resourcesDir) { + super(DEFAULT_GENERATION_ROOT.toFile()); + + //noinspection ResultOfMethodCallIgnored + DEFAULT_GENERATION_ROOT.toFile().mkdirs(); + + this.resourcesDir = resourcesDir; + + final String currentClasspath = getClasspathFromClassloader(ClassLoader.getSystemClassLoader()); + compiler = Compiler.javac() + .withOptions("-classpath", currentClasspath); + } + + public Path getResourcesDir() { + return resourcesDir; + } + + @Override + public Statement apply(final Statement base, final Description description) { + + return new Statement() { + @Override + public void evaluate() throws Throwable { + before(); + + try { + base.evaluate(); + after(); + } catch (Exception e) { + System.err.println("Failed working with folder: " + getRoot()); + throw new AssertionError(e); + } + } + }; + } + + public BaseAssertionGenerator buildAssertionGenerator() throws IOException { + BaseAssertionGenerator assertionGenerator = new BaseAssertionGenerator(); + assertionGenerator.setDirectoryWhereAssertionFilesAreGenerated(getRoot()); + return assertionGenerator; + } + + public Path packagePathFor(Class clazz) { + return getRoot().toPath() + .resolve(clazz.getPackage().getName().replace('.', File.separatorChar)); + } + + public File fileGeneratedFor(Class clazz) { + String generatedFileName = getSimpleNameWithOuterClassNotSeparatedByDots(clazz) + ASSERT_CLASS_FILE_SUFFIX; + return packagePathFor(clazz) + .resolve(generatedFileName) + .toFile(); + } + + public File abstractFileGeneratedFor(Class clazz) { + String generatedFileName = ABSTRACT_ASSERT_CLASS_PREFIX + + getSimpleNameWithOuterClassNotSeparatedByDots(clazz) + + ASSERT_CLASS_FILE_SUFFIX; + return packagePathFor(clazz) + .resolve(generatedFileName) + .toFile(); + } + + public void compileGeneratedFiles(Iterable files) { + List jfiles = new ArrayList<>(); + for (File file: files) { + try { + final URL url = file.toURI().toURL(); + jfiles.add(JavaFileObjects.forResource(url)); + } catch (MalformedURLException mfue) { + Assertions.failBecauseExceptionWasNotThrown(MalformedURLException.class); + } + } + + Compilation compilation = compiler.compile(jfiles); + + try { + + CompilationSubject.assertThat(compilation).succeeded(); + } catch (AssertionError ex) { + throw new AssertionError("Error with compilation. JAVAC options:\n" + compiler.options(), ex); + } + } + + public void compileGeneratedFiles(File... files) { + compileGeneratedFiles(Arrays.asList(files)); + } + + public void compileGeneratedFiles(Class... classes) { + List files = new ArrayList<>(classes.length); + for (Class clazz: classes) { + files.add(fileGeneratedFor(clazz)); + + // Handle abstract files, too! + File abstractFile = abstractFileGeneratedFor(clazz); + if (abstractFile.exists()) { + files.add(abstractFile); + } + } + + compileGeneratedFiles(files); + } + + public void assertGeneratedAssertClass(Class clazz, String expectedAssertFile, final boolean compileGenerated) throws IOException { + File expectedFile = resourcesDir.resolve(expectedAssertFile).toAbsolutePath().toFile(); + File actualFile = fileGeneratedFor(clazz); + assertThat(actualFile).hasSameContentAs(expectedFile); + + // compile it! + if (compileGenerated) { + compileGeneratedFiles(clazz); + } + } + + public void assertAbstractGeneratedAssertClass(Class clazz, String expectedAssertFile) { + File expectedFile = getResourcesDir().resolve(expectedAssertFile).toAbsolutePath().toFile(); + assertThat(abstractFileGeneratedFor(clazz)).hasSameContentAs(expectedFile); + } + + /** + * Returns the current classpaths of the given classloader including its parents. + * + * @throws IllegalArgumentException if the given classloader had classpaths which we could not + * determine or use for compilation. + */ + private static String getClasspathFromClassloader(ClassLoader currentClassloader) { + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + + // Add all URLClassloaders in the hirearchy till the system classloader. + List classloaders = new ArrayList<>(); + while(true) { + if (currentClassloader instanceof URLClassLoader) { + // We only know how to extract classpaths from URLClassloaders. + classloaders.add((URLClassLoader) currentClassloader); + } else { + throw new IllegalArgumentException("Classpath for compilation could not be extracted " + + "since given classloader is not an instance of URLClassloader"); + } + if (currentClassloader == systemClassLoader) { + break; + } + currentClassloader = currentClassloader.getParent(); + } + + Set classpaths = new LinkedHashSet<>(); + for (URLClassLoader classLoader : classloaders) { + for (URL url : classLoader.getURLs()) { + if (url.getProtocol().equals("file")) { + classpaths.add(url.getPath()); + } else { + throw new IllegalArgumentException("Given classloader consists of classpaths which are " + + "unsupported for compilation."); + } + } + } + + return Joiner.on(File.pathSeparatorChar).join(classpaths); + } +} 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 74c0a3c6..aaa84052 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 @@ -1,4 +1,4 @@ -/* +/** * 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 * 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 7c8b7f92..f5426818 100644 --- a/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java +++ b/src/test/java/org/assertj/assertions/generator/util/ClassUtilTest.java @@ -1,4 +1,4 @@ -/* +/** * 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 * diff --git a/src/test/resources/BooleanPredicates.expected.txt b/src/test/resources/BooleanPredicates.expected.txt index feaf4550..5769a28c 100644 --- a/src/test/resources/BooleanPredicates.expected.txt +++ b/src/test/resources/BooleanPredicates.expected.txt @@ -312,7 +312,7 @@ public class BooleanPredicatesAssert extends AbstractObjectAssert Date: Tue, 30 May 2017 13:40:44 -0400 Subject: [PATCH 5/5] Fixes #105 - Could not find predicate methods that collide * Added `findGetterDescriptionForField(FieldDescription base)` to check against all known prefixes for methods that clash * Extended test case for FieldPropertyClash to include predicate case --- .../generator/BaseAssertionGenerator.java | 17 +- .../description/ClassDescription.java | 51 +++++- .../assertions/generator/util/ClassUtil.java | 2 +- .../generator/data/FieldPropertyClash.java | 20 +++ .../resources/FieldPropertyClash.expected.txt | 148 ++++++++++++++++++ 5 files changed, 222 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java index 2bf76d75..5e583921 100644 --- a/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java +++ b/src/main/java/org/assertj/assertions/generator/BaseAssertionGenerator.java @@ -460,19 +460,14 @@ protected void generateAssertionsForPublicFields(StringBuilder assertionsForPubl } private String assertionContentForField(FieldDescription field, ClassDescription classDescription) { - final TypeToken owningType = field.getOwningType(); - final String fieldName = field.getName(); - final String fieldNameCap = capitalize(field.getName()); - try { - Method m = owningType.getRawType().getMethod("get" + fieldNameCap); - if (classDescription.getGettersDescriptions().contains(new GetterDescription(fieldName, owningType, m))) { - return ""; - } - } catch (NoSuchMethodException nsme) { - // ignore it, let flow keep going + // Check for getter existing + GetterDescription getter = classDescription.findGetterDescriptionForField(field); + if (getter != null) { + return ""; } + final String fieldName = field.getName(); String assertionContent = baseAssertionContentFor(field, classDescription); // we reuse template for properties to have consistent assertions for property and field but change the way we get @@ -500,7 +495,7 @@ private String assertionContentForField(FieldDescription field, ClassDescription assertionContent = replace(assertionContent, PREDICATE, field.getPredicate()); assertionContent = replace(assertionContent, PREDICATE_NEG, field.getNegativePredicate()); } - assertionContent = replace(assertionContent, PROPERTY_WITH_UPPERCASE_FIRST_CHAR, fieldNameCap); + assertionContent = replace(assertionContent, PROPERTY_WITH_UPPERCASE_FIRST_CHAR, capitalize(field.getName())); assertionContent = replace(assertionContent, PROPERTY_SIMPLE_TYPE, field.getTypeName(false, false)); assertionContent = replace(assertionContent, PROPERTY_ASSERT_TYPE, diff --git a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java index ec3b5be7..586d6a66 100644 --- a/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java +++ b/src/main/java/org/assertj/assertions/generator/description/ClassDescription.java @@ -13,12 +13,11 @@ package org.assertj.assertions.generator.description; import com.google.common.reflect.TypeToken; +import org.apache.commons.lang3.StringUtils; import org.assertj.assertions.generator.util.ClassUtil; +import org.assertj.assertions.generator.util.StringUtil; -import java.util.Collection; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; /** * @@ -101,6 +100,50 @@ public void addDeclaredGetterDescriptions(Collection declared public void addDeclaredFieldDescriptions(Set declaredFieldDescriptions) { this.declaredFieldsDescriptions.addAll(declaredFieldDescriptions); } + + public GetterDescription findGetterDescriptionForField(FieldDescription base) { + + final String capName = StringUtils.capitalize(base.getName()); + if (ClassUtil.isBoolean(base.getValueType())) { + // deal with predicates + + // Build a map for better look-up + Map fieldMap = new HashMap<>(); + for (GetterDescription getter: this.gettersDescriptions) { + fieldMap.put(getter.getOriginalMember().getName(), getter); + } + for (GetterDescription getter: this.declaredGettersDescriptions) { + fieldMap.put(getter.getOriginalMember().getName(), getter); + } + + for (String prefix: ClassUtil.PREDICATE_PREFIXES.keySet()) { + String propName = prefix + capName; + + GetterDescription getterDesc = fieldMap.get(propName); + if (getterDesc != null) { + return getterDesc; + } + } + } else { + + String propName = "get" + capName; + + for (GetterDescription desc: this.gettersDescriptions) { + if (Objects.equals(desc.getOriginalMember().getName(), propName)) { + return desc; + } + } + + for (GetterDescription desc: this.declaredGettersDescriptions) { + if (Objects.equals(desc.getOriginalMember().getName(), propName)) { + return desc; + } + } + } + + // wasn't found + return null; + } @Override public String toString() { 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 f1f45625..a293232d 100644 --- a/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java +++ b/src/main/java/org/assertj/assertions/generator/util/ClassUtil.java @@ -302,7 +302,7 @@ public static boolean isValidGetterName(String methodName) { static private final Pattern PREFIX_PATTERN; - static private final Map PREDICATE_PREFIXES; + static public final Map PREDICATE_PREFIXES; static private final Comparator LONGEST_TO_SHORTEST = new Comparator() { @Override diff --git a/src/test/java/org/assertj/assertions/generator/data/FieldPropertyClash.java b/src/test/java/org/assertj/assertions/generator/data/FieldPropertyClash.java index 63f55e9c..7abc35fd 100644 --- a/src/test/java/org/assertj/assertions/generator/data/FieldPropertyClash.java +++ b/src/test/java/org/assertj/assertions/generator/data/FieldPropertyClash.java @@ -20,4 +20,24 @@ public class FieldPropertyClash { public String getString() { return ""; } + + // joel-costigliola/assertj-assertions-generator#105 + // Predicate properties were not properly discerned vs non-predicate + public boolean isBoolean; + public boolean isBoolean() { return false; } + + public boolean isNotBoolean() { return false; } + + + public boolean shouldNotBeSomewhere; + public boolean shouldNotBeSomewhere() { return shouldNotBeSomewhere; } + + // different "tenses" + public boolean willBeOutside; + public boolean willNotBeOutside() { return willBeOutside; } + + // + public boolean willNotBeUpsideDown; + public boolean willBeUpsideDown() { return !willNotBeUpsideDown; } + } diff --git a/src/test/resources/FieldPropertyClash.expected.txt b/src/test/resources/FieldPropertyClash.expected.txt index 1a2be51d..da79bf4e 100644 --- a/src/test/resources/FieldPropertyClash.expected.txt +++ b/src/test/resources/FieldPropertyClash.expected.txt @@ -28,6 +28,114 @@ public class FieldPropertyClashAssert extends AbstractObjectAssert