Skip to content

Commit 2120a76

Browse files
committed
feat: construct fixture without class as param
It makes little sense to call a factory method with an object of the same class that we want to fixture, therefore creating a (potentially endless) recursion. Refs: JF-77
1 parent 17a37a5 commit 2120a76

File tree

5 files changed

+62
-23
lines changed

5 files changed

+62
-23
lines changed

src/main/java/com/github/nylle/javafixture/InstanceFactory.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public InstanceFactory(SpecimenFactory specimenFactory) {
5252
public <T> T construct(final SpecimenType<T> type) {
5353
return construct(type, new CustomizationContext(true));
5454
}
55+
5556
public <T> T construct(final SpecimenType<T> type, CustomizationContext customizationContext) {
5657
var constructors = type.getDeclaredConstructors()
5758
.stream()
@@ -70,14 +71,20 @@ public <T> T manufacture(final SpecimenType<T> type, CustomizationContext custom
7071
Collections.shuffle(factoryMethods);
7172
var results = factoryMethods
7273
.stream()
73-
.filter(x -> Modifier.isPublic(x.getModifiers()))
74+
.filter(method -> Modifier.isPublic(method.getModifiers()))
75+
.filter(method -> !hasSpecimenTypeAsParameter(method, type))
7476
.map(x -> manufactureOrNull(x, type, customizationContext))
7577
.filter(x -> x != null)
7678
.findFirst();
7779

7880
return results.orElseThrow(() -> new SpecimenException(format("Cannot manufacture %s", type.asClass())));
7981
}
8082

83+
private <T> boolean hasSpecimenTypeAsParameter(Method m, SpecimenType<T> type) {
84+
return stream(m.getGenericParameterTypes())
85+
.anyMatch(t -> t.getTypeName().equals(type.asClass().getName()));
86+
}
87+
8188
public <T> T instantiate(final SpecimenType<T> type) {
8289
try {
8390
return type.asClass().getDeclaredConstructor().newInstance();

src/test/java/com/github/nylle/javafixture/CharsetTest.java

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/test/java/com/github/nylle/javafixture/InstanceFactoryTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.github.nylle.javafixture.testobjects.factorymethod.ConstructorExceptionAndFactoryMethod;
44
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithArgument;
55
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithGenericArgument;
6+
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithItselfAsArgument;
7+
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithOnlyItselfAsArgument;
68
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithoutArgument;
79
import com.github.nylle.javafixture.testobjects.factorymethod.GenericClassWithFactoryMethodWithoutArgument;
810
import com.github.nylle.javafixture.testobjects.factorymethod.TestObjectWithNonPublicFactoryMethods;
@@ -55,6 +57,7 @@ void canCreateInstanceFromConstructor() {
5557
assertThat(result.getValue()).isInstanceOf(String.class);
5658
assertThat(result.getInteger()).isInstanceOf(Optional.class);
5759
}
60+
5861
@Test
5962
@DisplayName("fields not set by constructor are null")
6063
void fieldsNotSetByConstructorAreNull() {
@@ -66,6 +69,7 @@ void fieldsNotSetByConstructorAreNull() {
6669
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
6770
assertThat(result.getPrivateField()).isNull();
6871
}
72+
6973
@Test
7074
@DisplayName("using constructor is used for all instances")
7175
void usingConstructorIsRecursive() {
@@ -146,6 +150,26 @@ void factoryMethodWithArgument() {
146150
assertThat(result.getValue()).isNotNull();
147151
}
148152

153+
@Test
154+
@DisplayName("methods with class itself as argument should be filtered out")
155+
void shouldFilter() {
156+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
157+
158+
FactoryMethodWithItselfAsArgument result = sut.manufacture(fromClass(FactoryMethodWithItselfAsArgument.class), CustomizationContext.noContext());
159+
160+
assertThat(result.getValue()).isNull();
161+
}
162+
163+
@Test
164+
@DisplayName("if only methods with class itself are available, we should fail")
165+
void shouldFailWithoutValidFactoryMethod() {
166+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
167+
168+
assertThatExceptionOfType(SpecimenException.class)
169+
.isThrownBy(() -> sut.manufacture(fromClass(FactoryMethodWithOnlyItselfAsArgument.class), CustomizationContext.noContext()));
170+
171+
}
172+
149173
@Test
150174
@DisplayName("optional can be created (and may be empty)")
151175
void createOptional() {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.github.nylle.javafixture.testobjects.factorymethod;
2+
3+
public class FactoryMethodWithItselfAsArgument {
4+
5+
private String value;
6+
7+
private FactoryMethodWithItselfAsArgument(String value) {
8+
this.value = value;
9+
}
10+
public static FactoryMethodWithItselfAsArgument factoryMethod() {
11+
return new FactoryMethodWithItselfAsArgument(null);
12+
}
13+
public static FactoryMethodWithItselfAsArgument factoryMethodWithItselfAsArgument(FactoryMethodWithItselfAsArgument arg) {
14+
return new FactoryMethodWithItselfAsArgument("this factory method should have been filtered out!");
15+
}
16+
17+
public String getValue() {
18+
return value;
19+
}
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.github.nylle.javafixture.testobjects.factorymethod;
2+
3+
public class FactoryMethodWithOnlyItselfAsArgument {
4+
5+
private FactoryMethodWithOnlyItselfAsArgument() {}
6+
7+
public static FactoryMethodWithOnlyItselfAsArgument factoryMethodWithItselfAsArgument(FactoryMethodWithOnlyItselfAsArgument arg) {
8+
return new FactoryMethodWithOnlyItselfAsArgument();
9+
}
10+
}

0 commit comments

Comments
 (0)