Skip to content

Commit

Permalink
updated tests
Browse files Browse the repository at this point in the history
  • Loading branch information
elifKurtay committed Sep 24, 2024
1 parent 5dde7a4 commit ec7c055
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
*/
package io.micronaut.sourcegen.annotations;

import io.micronaut.core.annotation.Introspected;

import java.lang.annotation.*;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* The Utils annotation on a bean should generate toString, equals and hashCode implementations.
* The Equals annotation on a bean should generate an equals method.
* The method will be created in [BeanName]Utils class as a static method:
* public static boolean BeanNameUtils.equals(BeanName this, Object other)
*
* @author Elif Kurtay
* @since 1.3
Expand All @@ -31,10 +31,4 @@
@Retention(RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
public @interface Equals {

/**
* @return Array of annotations to apply on the utils
*/
Class<? extends Annotation>[] annotatedWith() default Introspected.class;

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
*/
package io.micronaut.sourcegen.annotations;

import io.micronaut.core.annotation.Introspected;

import java.lang.annotation.*;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* The Utils annotation on a bean should generate toString, equals and hashCode implementations.
* The HashCode annotation on a bean should generate a hashCode method.
* The method will be created in [BeanName]Utils class as a static method:
* public static int BeanNameUtils.hashCode(BeanName object)
*
* @author Elif Kurtay
* @since 1.3
Expand All @@ -31,10 +31,4 @@
@Retention(RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
public @interface HashCode {

/**
* @return Array of annotations to apply on the utils
*/
Class<? extends Annotation>[] annotatedWith() default Introspected.class;

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
*/
package io.micronaut.sourcegen.annotations;

import io.micronaut.core.annotation.Introspected;

import java.lang.annotation.*;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* The Utils annotation on a bean should generate toString, equals and hashCode implementations.
* The ToString annotation on a bean should generate a toString method.
* The method will be created in [BeanName]Utils class as a static method:
* public static String BeanNameUtils.toString(BeanName object)
*
* @author Elif Kurtay
* @since 1.3
Expand All @@ -31,10 +31,4 @@
@Retention(RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
public @interface ToString {

/**
* @return Array of annotations to apply on the utils
*/
Class<? extends Annotation>[] annotatedWith() default Introspected.class;

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@
import java.util.*;
import javax.lang.model.element.Modifier;

import static io.micronaut.sourcegen.generator.visitors.BuilderAnnotationVisitor.*;

/**
* The visitor that generates the util functions of a bean.
* The visitor that generates the Utils class of a bean.
* The Utils class can have functions substituting toString, equals, and hashcode.
* However, each method needs to be annotated to be generated.
* \@ToString annotation for toString function
* \@Equals annotation for equals function
* \@HashCode annotation for hashCode function
*
* @author Elif Kurtay
* @since 1.3
Expand Down Expand Up @@ -77,10 +80,10 @@ public void visitClass(ClassElement element, VisitorContext context) {
ClassDef.ClassDefBuilder utilsBuilder = ClassDef.builder(utilsClassName)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);

// TODO: should I check for properties that have getters?
// TODO: add checks for properties that have getters?
List<PropertyElement> properties = element.getBeanProperties();

// create the utils functions
// create the utils functions if they are annotated
if (element.hasStereotype(ToString.class)) {
createToStringMethod(utilsBuilder, element.getSimpleName(), properties);
}
Expand Down Expand Up @@ -126,7 +129,9 @@ public void visitClass(ClassElement element, VisitorContext context) {
}
}

/* toString method
/*
Creates a toString method with signature:
public static String BeanNameUtils.toString(BeanName object)
*/
private static void createToStringMethod(ClassDef.ClassDefBuilder classDefBuilder, String objectName, List<PropertyElement> properties) {
List<StatementDef> statements = new ArrayList<>();
Expand Down Expand Up @@ -180,20 +185,22 @@ private static void createToStringMethod(ClassDef.ClassDefBuilder classDefBuilde
classDefBuilder.addMethod(method);
}

/* complete equals method
/*
Creates an equals method with signature:
public static boolean BeanNameUtils.equals(BeanName object1, Object object2)
*/
private static void createEqualsMethod(ClassDef.ClassDefBuilder classDefBuilder, String objectName, List<PropertyElement> properties) {
MethodDef method = MethodDef.builder("equals")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(boolean.class)
.addParameter("firstObject", TypeDef.of(Object.class))
.addParameter("first", ClassTypeDef.of(objectName))
.addParameter("secondObject", TypeDef.of(Object.class))
.build((self, parameterDef) -> {
// local variables needed
VariableDef classname = new VariableDef.Local(objectName, ClassTypeDef.of(objectName));
VariableDef arrays = new VariableDef.Local("java.util.Arrays", ClassTypeDef.of(java.util.Arrays.class));
List<StatementDef> statements = new ArrayList<>();
VariableDef.Local firstObject = new VariableDef.Local("first", classname.type());
VariableDef firstObject = parameterDef.get(0).asVariable();
VariableDef.Local secondObject = new VariableDef.Local("second", classname.type());
VariableDef.Local bothNullCondition = new VariableDef.Local("bothNullCondition", TypeDef.of(boolean.class));
VariableDef.Local equalsCondition = new VariableDef.Local("equalsCondition", TypeDef.of(boolean.class));
Expand All @@ -207,15 +214,12 @@ private static void createEqualsMethod(ClassDef.ClassDefBuilder classDefBuilder,
.asConditionIf(ExpressionDef.constant(true).returning()),
new StatementDef.DefineAndAssign(
isCorrectInstance,
new ExpressionDef.Condition(" && ",
parameterDef.get(0).asVariable().asCondition(" instanceof ", classname),
parameterDef.get(1).asVariable().asCondition(" instanceof ", classname))
parameterDef.get(1).asVariable().asCondition(" instanceof ", classname)
),
new StatementDef.If(
new ExpressionDef.Condition(" == ", isCorrectInstance, ExpressionDef.constant(false)),
ExpressionDef.constant(false).returning()
),
new StatementDef.DefineAndAssign(firstObject, new ExpressionDef.Cast(classname.type(), parameterDef.get(0).asVariable())),
new StatementDef.DefineAndAssign(secondObject, new ExpressionDef.Cast(classname.type(), parameterDef.get(1).asVariable())),
new StatementDef.DefineAndAssign(bothNullCondition, ExpressionDef.constant(false)),
new StatementDef.DefineAndAssign(equalsCondition, ExpressionDef.constant(false)),
Expand Down Expand Up @@ -287,7 +291,9 @@ private static void createEqualsMethod(ClassDef.ClassDefBuilder classDefBuilder,
classDefBuilder.addMethod(method);
}

/* complete hashCode method
/*
Creates a hashCode method with signature:
public static int BeanNameUtils.hashCode(BeanName object)
*/
private static void createHashCodeMethod(ClassDef.ClassDefBuilder classDefBuilder, String objectName, List<PropertyElement> properties) {
MethodDef method = MethodDef.builder("hashCode")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.micronaut.sourcegen.example;


//tag::clazz[]
import io.micronaut.sourcegen.annotations.Equals;
import io.micronaut.sourcegen.annotations.HashCode;
Expand All @@ -27,26 +26,53 @@
@Equals
@HashCode
public class Person4 {
public enum Title {
MRS,
MR,
MS
}

private long id;
private Title title;
private String name;
private byte[] bytes;

public Person4(long id, String name, byte[] bytes) {
public Person4(long id, Title title, String name, byte[] bytes) {
this.id = id;
this.title = title;
this.name = name;
this.bytes = Arrays.copyOf(bytes, bytes.length);
this.bytes = (bytes != null) ? Arrays.copyOf(bytes, bytes.length) : null;
}

public long getId() {
return id;
}

public Title getTitle() {
return title;
}

public String getName() {
return name;
}

public byte[] getBytes() {
return bytes;
}

@Override
public String toString() {
return Person4Utils.toString(this);
}

@Override
public int hashCode() {
return Person4Utils.hashCode(this);
}

@Override
public boolean equals(Object obj) {
return Person4Utils.equals(this, obj);
}
}
//end::clazz[]
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,63 @@ public class PersonUtilsTest {

@Test
public void testToString() {
var person = new Person4(123L, "Cédric", new byte[]{1,2,3});
var person = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});

assertNotNull(Person4Utils.toString(person));
assertTrue(Person4Utils.toString(person).contains("Person4["));
assertTrue(person.toString().contains("Person4["));
assertEquals("Person4[id=123, title=MR, name=Cédric, bytes=[1, 2, 3]]", person.toString());
}

@Test
public void testEqualsWithCorrectObjects() {
var person = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personSame = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personDiffPrimitive = new Person4(124L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personDiffEnum = new Person4(123L, Person4.Title.MRS,"Cédric", new byte[]{1,2,3});
var personDiffObject = new Person4(123L, Person4.Title.MR,"Cédric Jr.", new byte[]{1,2,3});
var personDiffArray = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,4});

assertNotNull(Person4Utils.equals(person, personSame));

assertTrue(person.equals(person));
assertTrue(person.equals(personSame));

assertFalse(person.equals(personDiffPrimitive));
assertFalse(person.equals(personDiffEnum));
assertFalse(person.equals(personDiffObject));
assertFalse(person.equals(personDiffArray));
}

@Test
public void testEquals() {
var person = new Person4(123L, "Cédric", new byte[]{1,2,3});
var personSame = new Person4(123L, "Cédric", new byte[]{1,2,3});
var personDiffAll = new Person4(124L, "Cédric 2", new byte[]{1,2,3, 4});
var personDiffPrimitive = new Person4(124L, "Cédric", new byte[]{1,2,3});
var personDiffObject = new Person4(123L, "Cédric", new byte[]{1,2,3, 4});

assertTrue(Person4Utils.equals(person, personSame));
assertTrue(Person4Utils.equals(person, person));
assertFalse(Person4Utils.equals(person, personDiffAll));
assertFalse(Person4Utils.equals(person, personDiffPrimitive));
assertFalse(Person4Utils.equals(person, personDiffObject));
public void testEqualsWithNulls() {
var person = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personDoubleNull1 = new Person4(123L, Person4.Title.MR,null, new byte[]{1,2,3});
var personDoubleNull2 = new Person4(123L, Person4.Title.MR,null, new byte[]{1,2,3});
var personSingleNull = new Person4(124L, Person4.Title.MR,"Cédric", null);

assertFalse(person.equals(null));
assertFalse(person.equals(new Object()));

assertTrue(personDoubleNull1.equals(personDoubleNull2));
assertFalse(personSingleNull.equals(person));
assertFalse(person.equals(personSingleNull));
}

@Test
public void testHashCode() {
var person = new Person4(123L, "Cédric", new byte[]{1,2,3});
var personSame = new Person4(123L, "Cédric", new byte[]{1,2,3});
var personDiffAll = new Person4(124L, "Cédric 2", new byte[]{1,2,3, 4});
assertEquals(Person4Utils.hashCode(person), Person4Utils.hashCode(personSame));
assertNotEquals(Person4Utils.hashCode(person), Person4Utils.hashCode(personDiffAll));
}
var person = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personSame = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personDiffPrimitive = new Person4(124L, Person4.Title.MR,"Cédric", new byte[]{1,2,3});
var personDiffEnum = new Person4(123L, Person4.Title.MRS,"Cédric", new byte[]{1,2,3});
var personDiffObject = new Person4(123L, Person4.Title.MR,"Cédric Jr.", new byte[]{1,2,3});
var personDiffArray = new Person4(123L, Person4.Title.MR,"Cédric", new byte[]{1,2,4});

assertNotNull(Person4Utils.hashCode(person));
assertEquals(person.hashCode(), person.hashCode());
assertEquals(person.hashCode(), personSame.hashCode());
assertNotEquals(person.hashCode(), personDiffPrimitive.hashCode());
assertNotEquals(person.hashCode(), personDiffEnum.hashCode());
assertNotEquals(person.hashCode(), personDiffObject.hashCode());
assertNotEquals(person.hashCode(), personDiffArray.hashCode());
}
}

0 comments on commit ec7c055

Please sign in to comment.