Skip to content

Commit

Permalink
feat: return result-object from instantiators
Browse files Browse the repository at this point in the history
The result contains the outcome of the attempt to instantiate the class.
Previously, only null was returned if the attempt failed; now the error
message is being included.
  • Loading branch information
jk-idealo committed Oct 3, 2024
1 parent 87937b3 commit f079468
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static <T> BuilderInstantiator<T> create(Method builderMethodCandidate, S
.orElse(null);
}

public T invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
public Result<T> invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
try {
var builder = builderMethod.invoke(null, new Object[]{});

Expand All @@ -42,9 +42,9 @@ public T invoke(SpecimenFactory specimenFactory, CustomizationContext customizat
});
}

return (T) buildMethod.invoke(builder, new Object[]{});
return Result.of((T) buildMethod.invoke(builder, new Object[]{}));
} catch (InvocationTargetException | IllegalAccessException ex) {
return null;
return Result.empty(ex.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.nylle.javafixture.SpecimenType;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Map;
Expand All @@ -23,13 +24,15 @@ public static <T> ConstructorInstantiator<T> create(java.lang.reflect.Constructo
return new ConstructorInstantiator<>(constructor);
}

public T invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
public Result<T> invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
try {
return constructor.newInstance(stream(constructor.getParameters())
return Result.of(constructor.newInstance(stream(constructor.getParameters())
.map(p -> createParameter(p, specimenFactory, customizationContext))
.toArray());
} catch(Exception ex) {
return null;
.toArray()));
} catch (InvocationTargetException ex) {
return Result.empty(ex.getTargetException().getMessage());
} catch (Exception ex) {
return Result.empty(ex.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,18 @@ public static <T> FactoryMethodInstantiator<T> create(Method factoryMethod, Spec
return new FactoryMethodInstantiator<>(factoryMethod, targetType);
}

public T invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
public Result<T> invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
try {
List<Object> arguments = new ArrayList<>();
for (int i = 0; i < factoryMethod.getParameterCount(); i++) {
var genericParameterType = factoryMethod.getGenericParameterTypes()[i];
var specimen = specimenFactory.build(targetType.isParameterized()
? targetType.getGenericTypeArgument(i)
: SpecimenType.fromClass(genericParameterType));
var o = specimen.create(customizationContext, new Annotation[0]);
arguments.add(o);
: SpecimenType.fromClass(factoryMethod.getGenericParameterTypes()[i]));
arguments.add(specimen.create(customizationContext, new Annotation[0]));
}
return (T) factoryMethod.invoke(null, arguments.toArray());
return Result.of((T) factoryMethod.invoke(null, arguments.toArray()));
} catch (Exception ex) {
return null;
return Result.empty(ex.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@

public interface Instantiator<T> {

T invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext);
Result<T> invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext);

class Result<T> {
private T value;
private String message;

private Result(T value, String message) {
this.value = value;
this.message = message;
}

public static <T> Result<T> of(T value) {
if(value == null) {
return new Result<T>(null, "result was null");
}
return new Result<T>(value, null);
}

public static <T> Result<T> empty(String message) {
return new Result<T>(null, message);
}

public T getValue() {
return value;
}

public String getMessage() {
return message;
}

public boolean isPresent() {
return value != null;
}

public boolean isEmpty() {
return value == null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.nylle.javafixture.annotations.testcases.TestCase;
import com.github.nylle.javafixture.annotations.testcases.TestWithCases;
import com.github.nylle.javafixture.instantiation.BuilderInstantiator;
import com.github.nylle.javafixture.testobjects.ClassWithBuilder;
import com.github.nylle.javafixture.testobjects.ITestGeneric;
import com.github.nylle.javafixture.testobjects.TestAbstractClass;
Expand Down Expand Up @@ -59,7 +60,6 @@
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;

import static com.github.nylle.javafixture.CustomizationContext.noContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

Expand Down Expand Up @@ -375,14 +375,12 @@ class FindBuilders {

@Test
void returnsListOfBuilders() {
var specimenFactory = new SpecimenFactory(new Context(new Configuration()));

var sut = new SpecimenType<ClassWithBuilder>(){};

var actual = sut.findBuilders();

assertThat(actual).hasSize(1);
assertThat(actual.get(0).invoke(specimenFactory, noContext())).isInstanceOf(ClassWithBuilder.class);
assertThat(actual.get(0)).isInstanceOf(BuilderInstantiator.class);
}

@TestWithCases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ void invokeReturnsBuiltObjectWithAllMethodsCalled() throws NoSuchMethodException

var result = sut.invoke(new SpecimenFactory(new Context(new Configuration())), CustomizationContext.noContext());

assertThat(result).isInstanceOf(ClassWithBuilder.class);
assertThat(result.getValue()).isInstanceOf(ClassWithBuilder.class);

var actual = (ClassWithBuilder) result;
var actual = (ClassWithBuilder) result.getValue();

assertThat(actual.getNumber()).isNotNull();
assertThat(actual.getString()).isNotNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.nylle.javafixture.CustomizationContext;
import com.github.nylle.javafixture.SpecimenFactory;
import com.github.nylle.javafixture.testobjects.TestObject;
import com.github.nylle.javafixture.testobjects.withconstructor.ConstructorExceptionAndNoFactoryMethod;
import com.github.nylle.javafixture.testobjects.withconstructor.TestObjectWithConstructedField;
import com.github.nylle.javafixture.testobjects.withconstructor.TestObjectWithGenericConstructor;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -25,9 +26,9 @@ void canCreateInstanceFromConstructor() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of(), Map.of(), false));

assertThat(actual).isInstanceOf(TestObjectWithGenericConstructor.class);
assertThat(actual.getValue()).isInstanceOf(String.class);
assertThat(actual.getInteger()).isInstanceOf(Optional.class);
assertThat(actual.getValue()).isInstanceOf(TestObjectWithGenericConstructor.class);
assertThat(actual.getValue().getValue()).isInstanceOf(String.class);
assertThat(actual.getValue().getInteger()).isInstanceOf(Optional.class);
}

@Test
Expand All @@ -37,8 +38,8 @@ void fieldsNotSetByConstructorAreNull() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of(), Map.of(), false));

assertThat(actual).isInstanceOf(TestObjectWithGenericConstructor.class);
assertThat(actual.getPrivateField()).isNull();
assertThat(actual.getValue()).isInstanceOf(TestObjectWithGenericConstructor.class);
assertThat(actual.getValue().getPrivateField()).isNull();
}

@Test
Expand All @@ -49,7 +50,7 @@ void argumentsCanBeCustomized() throws NoSuchMethodException {
// use arg0, because .class files do not store formal parameter names by default
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of(), Map.of("arg0", "customized"), true));

assertThat(actual.getValue()).isEqualTo("customized");
assertThat(actual.getValue().getValue()).isEqualTo("customized");
}

@Test
Expand All @@ -59,9 +60,9 @@ void usingConstructorIsRecursive() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of(), Map.of(), true));

assertThat(actual).isInstanceOf(TestObjectWithConstructedField.class);
assertThat(actual.getTestObjectWithGenericConstructor().getPrivateField()).isNull();
assertThat(actual.getNotSetByConstructor()).isNull();
assertThat(actual.getValue()).isInstanceOf(TestObjectWithConstructedField.class);
assertThat(actual.getValue().getTestObjectWithGenericConstructor().getPrivateField()).isNull();
assertThat(actual.getValue().getNotSetByConstructor()).isNull();
}

@Test
Expand All @@ -72,7 +73,7 @@ void constructorArgumentsAreUsedOnce() throws NoSuchMethodException {
// use arg0, because .class files do not store formal parameter names by default
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of(), Map.of("arg0", 2), true));

assertThat(actual.getSetByConstructor()).isEqualTo(2);
assertThat(actual.getValue().getSetByConstructor()).isEqualTo(2);
}

@Test
Expand All @@ -83,6 +84,16 @@ void ignoredConstructorArgsAreRespected() throws NoSuchMethodException {
// use arg0, because .class files do not store formal parameter names by default
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of("arg0"), Map.of(), true));

assertThat(actual.getSetByConstructor()).isEqualTo(0);
assertThat(actual.getValue().getSetByConstructor()).isEqualTo(0);
}

@Test
void xxx() throws NoSuchMethodException {
var sut = ConstructorInstantiator.create(ConstructorExceptionAndNoFactoryMethod.class.getConstructor());

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), new CustomizationContext(List.of(), Map.of(), true));

assertThat(actual.isEmpty()).isTrue();
assertThat(actual.getMessage()).isEqualTo("expected for tests");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void factoryMethodWithoutArgument() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual.getValue()).isEqualTo(42);
assertThat(actual.getValue().getValue()).isEqualTo(42);
}

@Test
Expand All @@ -37,7 +37,7 @@ void returnsInstanceOfClassUsingFactoryMethodWithArguments() throws NoSuchMethod

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual.getValue()).isNotNull();
assertThat(actual.getValue().getValue()).isNotNull();
}

@Test
Expand All @@ -47,7 +47,7 @@ void factoryMethodWithGenericArgument() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual.getValue()).isNotNull();
assertThat(actual.getValue().getValue()).isNotNull();
}

@Test
Expand All @@ -57,7 +57,7 @@ void returnsInstanceOfAbstractClassUsingFactoryMethod() throws NoSuchMethodExcep

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual).isInstanceOf(Charset.class);
assertThat(actual.getValue()).isInstanceOf(Charset.class);
}

@Test
Expand All @@ -67,9 +67,9 @@ void createOptionalWithArgument() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual).isInstanceOf(Optional.class);
assertThat(actual).isNotEmpty();
assertThat(actual.get()).isInstanceOf(String.class);
assertThat(actual.getValue()).isInstanceOf(Optional.class);
assertThat(actual.getValue()).isNotEmpty();
assertThat(actual.getValue().get()).isInstanceOf(String.class);
}

@Test
Expand All @@ -79,8 +79,8 @@ void createOptionalWithoutArgument() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual).isInstanceOf(Optional.class);
assertThat(actual).isEmpty();
assertThat(actual.getValue()).isInstanceOf(Optional.class);
assertThat(actual.getValue()).isEmpty();
}

@Test
Expand All @@ -90,7 +90,7 @@ void genericNoArgumentFactoryMethod() throws NoSuchMethodException {

var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());

assertThat(actual).isNotNull();
assertThat(actual.getValue()).isEqualTo(42);
assertThat(actual.getValue()).isNotNull();
assertThat(actual.getValue().getValue()).isEqualTo(42);
}
}

0 comments on commit f079468

Please sign in to comment.