Skip to content

Commit 0a36c9e

Browse files
committed
fix: allow generic factory method w/o arguments
Otherwise we will never have an Optional.empty() Refs: JF-63
1 parent 93782e5 commit 0a36c9e

File tree

8 files changed

+111
-97
lines changed

8 files changed

+111
-97
lines changed

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import java.lang.reflect.Method;
1313
import java.lang.reflect.Modifier;
1414
import java.lang.reflect.Proxy;
15-
import java.lang.reflect.Type;
1615
import java.util.ArrayDeque;
1716
import java.util.ArrayList;
1817
import java.util.Collection;
@@ -129,16 +128,16 @@ private <T> T createProxyForAbstract(final SpecimenType<T> type, final Map<Strin
129128

130129
private <T> T manufactureOrNull(final Method method, SpecimenType<T> type) {
131130
try {
132-
Type[] parameterTypes;
133-
if (type.isParameterized()) {
134-
parameterTypes = type.getGenericTypeArguments();
135-
} else {
136-
parameterTypes = method.getGenericParameterTypes();
131+
List<Object> arguments = new ArrayList<>();
132+
for (int i = 0; i < method.getParameterCount(); i++) {
133+
var genericParameterType = method.getGenericParameterTypes()[i];
134+
var specimen = specimenFactory.build(type.isParameterized()
135+
? SpecimenType.fromClass(type.getGenericTypeArgument(i))
136+
: SpecimenType.fromClass(genericParameterType));
137+
var o = specimen.create(new Annotation[0]);
138+
arguments.add(o);
137139
}
138-
return (T) method.invoke(null, stream(parameterTypes)
139-
.map(t -> specimenFactory.build(SpecimenType.fromClass(t)))
140-
.map(s -> s.create(new Annotation[0]))
141-
.toArray());
140+
return (T) method.invoke(null, arguments.toArray());
142141
} catch (Exception ex) {
143142
return null;
144143
}

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

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,6 @@ void canCreateParameterizedObject() {
350350
assertThat(result.getAClass()).isEqualTo(Object.class);
351351

352352
assertThat(result.getOptional()).isInstanceOf(Optional.class);
353-
assertThat(result.getOptional().isPresent()).isTrue();
354-
assertThat(result.getOptional().get()).isInstanceOf(Boolean.class);
355353
}
356354

357355
@Test
@@ -363,16 +361,10 @@ void canCreateNestedParameterizedObject() {
363361
assertThat(result).isInstanceOf(TestObjectWithNestedGenerics.class);
364362

365363
assertThat(result.getOptionalGeneric()).isInstanceOf(Optional.class);
366-
assertThat(result.getOptionalGeneric().isPresent()).isTrue();
367-
assertThat(result.getOptionalGeneric().get()).isInstanceOf(TestObjectGeneric.class);
368-
assertThat(result.getOptionalGeneric().get().getT()).isInstanceOf(String.class);
369-
assertThat(result.getOptionalGeneric().get().getU()).isInstanceOf(Integer.class);
370364

371365
assertThat(result.getGenericOptional()).isInstanceOf(TestObjectGeneric.class);
372366
assertThat(result.getGenericOptional().getT()).isInstanceOf(String.class);
373367
assertThat(result.getGenericOptional().getU()).isInstanceOf(Optional.class);
374-
assertThat(result.getGenericOptional().getU()).isPresent();
375-
assertThat(result.getGenericOptional().getU().get()).isInstanceOf(Integer.class);
376368
}
377369

378370
@Test
@@ -388,12 +380,8 @@ void canCreateNestedParameterizedInterfaces() {
388380
assertThat(result.getTestGeneric().getU()).isInstanceOf(ITestGenericInside.class);
389381

390382
assertThat(result.getTestGeneric().getU().getOptionalBoolean()).isInstanceOf(Optional.class);
391-
assertThat(result.getTestGeneric().getU().getOptionalBoolean()).isPresent();
392-
assertThat(result.getTestGeneric().getU().getOptionalBoolean().get()).isInstanceOf(Boolean.class);
393383

394384
assertThat(result.getTestGeneric().getU().getOptionalT()).isInstanceOf(Optional.class);
395-
assertThat(result.getTestGeneric().getU().getOptionalT()).isPresent();
396-
assertThat(result.getTestGeneric().getU().getOptionalT().get()).isInstanceOf(Integer.class);
397385

398386
assertThat(result.getTestGeneric().getU().getTestGeneric()).isInstanceOf(TestObjectGeneric.class);
399387
assertThat(result.getTestGeneric().getU().getTestGeneric().getT()).isInstanceOf(String.class);
@@ -411,8 +399,6 @@ void createThroughRandomConstructor() {
411399
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
412400
assertThat(result.getValue()).isInstanceOf(String.class);
413401
assertThat(result.getInteger()).isInstanceOf(Optional.class);
414-
assertThat(result.getInteger()).isPresent();
415-
assertThat(result.getInteger().get()).isInstanceOf(Integer.class);
416402
assertThat(result.getPrivateField()).isNull();
417403
}
418404
}
@@ -429,8 +415,6 @@ void canCreateGenericObject() {
429415
assertThat(result).isInstanceOf(TestObjectGeneric.class);
430416
assertThat(result.getT()).isInstanceOf(String.class);
431417
assertThat(result.getU()).isInstanceOf(Optional.class);
432-
assertThat(result.getU()).isPresent();
433-
assertThat(result.getU().get()).isInstanceOf(Integer.class);
434418
}
435419

436420
@Test
@@ -444,11 +428,7 @@ void canCreateGenericInterface() {
444428
assertThat(result.getT()).isInstanceOf(String.class);
445429
assertThat(result.getU()).isInstanceOf(ITestGenericInside.class);
446430
assertThat(result.getU().getOptionalBoolean()).isInstanceOf(Optional.class);
447-
assertThat(result.getU().getOptionalBoolean()).isPresent();
448-
assertThat(result.getU().getOptionalBoolean().get()).isInstanceOf(Boolean.class);
449431
assertThat(result.getU().getOptionalT()).isInstanceOf(Optional.class);
450-
assertThat(result.getU().getOptionalT()).isPresent();
451-
assertThat(result.getU().getOptionalT().get()).isInstanceOf(Integer.class);
452432
assertThat(result.getU().getTestGeneric()).isInstanceOf(TestObjectGeneric.class);
453433
assertThat(result.getU().getTestGeneric().getT()).isInstanceOf(String.class);
454434
assertThat(result.getU().getTestGeneric().getU()).isInstanceOf(Integer.class);
@@ -468,9 +448,6 @@ void canCreateMapsAndLists() {
468448
var innerList = subMap.values().iterator().next();
469449
assertThat(innerList).isNotEmpty();
470450
assertThat(innerList.get(0)).isInstanceOf(Optional.class);
471-
assertThat(innerList.get(0)).isPresent();
472-
assertThat(innerList.get(0).get()).isInstanceOf(String.class);
473-
assertThat(innerList.get(0).get()).isNotEmpty();
474451
}
475452

476453
@Test
@@ -506,8 +483,6 @@ void canCreateMany() {
506483
assertThat(result).isNotNull();
507484
assertThat(result).isNotEmpty();
508485
assertThat(result.get(0)).isInstanceOf(Optional.class);
509-
assertThat(result.get(0)).isPresent();
510-
assertThat(result.get(0).get()).isInstanceOf(Integer.class);
511486
}
512487

513488
@Test
@@ -524,9 +499,6 @@ void canAddManyTo() {
524499
assertThat(result.get(0)).isPresent();
525500
assertThat(result.get(0).get()).isEqualTo("existing");
526501
assertThat(result.get(1)).isInstanceOf(Optional.class);
527-
assertThat(result.get(1)).isPresent();
528-
assertThat(result.get(1).get()).isInstanceOf(String.class);
529-
assertThat(result.get(1).get()).isNotEmpty();
530502
}
531503

532504
@Test
@@ -574,9 +546,6 @@ void createThroughRandomConstructor() {
574546
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
575547
assertThat(result.getValue()).isInstanceOf(String.class);
576548
assertThat(result.getInteger()).isInstanceOf(Optional.class);
577-
assertThat(result.getInteger()).isPresent();
578-
assertThat(result.getInteger().get()).isInstanceOf(Integer.class);
579-
assertThat(result.getPrivateField()).isNull();
580549
}
581550

582551
}

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

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package com.github.nylle.javafixture;
22

33
import com.github.nylle.javafixture.testobjects.TestObjectWithGenericConstructor;
4-
import com.github.nylle.javafixture.testobjects.factorymethod.ConstructorExceptionAndFactoryMethod;
5-
import com.github.nylle.javafixture.testobjects.factorymethod.TestObjectWithNonPublicFactoryMethods;
64
import com.github.nylle.javafixture.testobjects.TestObjectWithPrivateConstructor;
5+
import com.github.nylle.javafixture.testobjects.factorymethod.ConstructorExceptionAndFactoryMethod;
76
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithArgument;
87
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithGenericArgument;
98
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithoutArgument;
9+
import com.github.nylle.javafixture.testobjects.factorymethod.GenericClassWithFactoryMethodWithoutArgument;
10+
import com.github.nylle.javafixture.testobjects.factorymethod.TestObjectWithNonPublicFactoryMethods;
1011
import org.junit.jupiter.api.DisplayName;
1112
import org.junit.jupiter.api.Nested;
1213
import org.junit.jupiter.api.Test;
@@ -38,70 +39,82 @@
3839

3940
class InstanceFactoryTest {
4041

41-
@Test
42-
void canCreateInstanceFromConstructor() {
43-
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
44-
45-
TestObjectWithGenericConstructor result = sut.construct(fromClass(TestObjectWithGenericConstructor.class));
42+
@Nested
43+
@DisplayName("when using constructor")
44+
class UsingConstructor {
4645

47-
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
48-
assertThat(result.getValue()).isInstanceOf(String.class);
49-
assertThat(result.getInteger()).isInstanceOf(Optional.class);
50-
assertThat(result.getInteger()).isPresent();
51-
assertThat(result.getInteger().get()).isInstanceOf(Integer.class);
52-
}
46+
@Test
47+
@DisplayName("instance is created from random constructor")
48+
void canCreateInstanceFromConstructor() {
49+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
5350

54-
@Test
55-
void fieldsNotSetByConstructorAreNull() {
51+
TestObjectWithGenericConstructor result = sut.construct(fromClass(TestObjectWithGenericConstructor.class));
5652

57-
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
53+
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
54+
assertThat(result.getValue()).isInstanceOf(String.class);
55+
assertThat(result.getInteger()).isInstanceOf(Optional.class);
56+
assertThat(result.getInteger()).isPresent();
57+
assertThat(result.getInteger().get()).isInstanceOf(Integer.class);
58+
}
5859

59-
TestObjectWithGenericConstructor result = sut.construct(fromClass(TestObjectWithGenericConstructor.class));
60+
@Test
61+
@DisplayName("fields not set by constructor are null")
62+
void fieldsNotSetByConstructorAreNull() {
6063

61-
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
62-
assertThat(result.getPrivateField()).isNull();
63-
}
64+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
6465

65-
@Test
66-
void canOnlyUsePublicConstructor() {
67-
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
66+
TestObjectWithGenericConstructor result = sut.construct(fromClass(TestObjectWithGenericConstructor.class));
6867

69-
assertThatExceptionOfType(SpecimenException.class)
70-
.isThrownBy(() -> sut.construct(fromClass(TestObjectWithPrivateConstructor.class)))
71-
.withMessageContaining("Cannot manufacture class")
72-
.withNoCause();
73-
}
74-
75-
@Test
76-
void canCreateInstanceFromAbstractClassUsingFactoryMethod() {
77-
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
68+
assertThat(result).isInstanceOf(TestObjectWithGenericConstructor.class);
69+
assertThat(result.getPrivateField()).isNull();
70+
}
7871

79-
var actual = sut.manufacture(new SpecimenType<Charset>() {});
72+
@Test
73+
@DisplayName("construction will fail if no public constructor is available")
74+
void canOnlyUsePublicConstructor() {
75+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
8076

81-
assertThat(actual).isInstanceOf(Charset.class);
82-
}
77+
assertThatExceptionOfType(SpecimenException.class)
78+
.isThrownBy(() -> sut.construct(fromClass(TestObjectWithPrivateConstructor.class)))
79+
.withMessageContaining("Cannot manufacture class")
80+
.withNoCause();
81+
}
8382

84-
@Test
85-
void useFactoryMethodWhenNoConstructorExists() {
86-
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
83+
@Test
84+
@DisplayName("will fallback to factory method when no public constructor exists")
85+
void useFactoryMethodWhenNoConstructorExists() {
86+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
8787

88-
FactoryMethodWithoutArgument result = sut.construct(fromClass(FactoryMethodWithoutArgument.class));
88+
FactoryMethodWithoutArgument result = sut.construct(fromClass(FactoryMethodWithoutArgument.class));
8989

90-
assertThat(result.getValue()).isEqualTo(42);
91-
}
90+
assertThat(result.getValue()).isEqualTo(42);
91+
}
9292

93-
@Test
94-
void fallbackToFactoryMethodWhenConstructorThrowsException() {
95-
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
93+
@Test
94+
@DisplayName("will fallback to factor method when constructor fails")
95+
void fallbackToFactoryMethodWhenConstructorThrowsException() {
96+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
9697

97-
ConstructorExceptionAndFactoryMethod result = sut.construct(new SpecimenType<ConstructorExceptionAndFactoryMethod>() {});
98+
var result = sut.construct(new SpecimenType<ConstructorExceptionAndFactoryMethod>() {});
9899

99-
assertThat(result.getValue()).isNotNull();
100+
assertThat(result.getValue()).isNotNull();
101+
}
100102
}
101103

102104
@Nested
103105
@DisplayName("when manufacturing using factory methods")
104106
class FactoryMethods {
107+
108+
@Test
109+
@DisplayName("factory method from abstract class is used when present")
110+
void canCreateInstanceFromAbstractClassUsingFactoryMethod() {
111+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
112+
113+
var actual = sut.manufacture(new SpecimenType<Charset>() {});
114+
115+
assertThat(actual).isInstanceOf(Charset.class);
116+
}
117+
105118
@Test
106119
@DisplayName("only public methods will be used")
107120
void canOnlyUsePublicFactoryMethods() {
@@ -112,7 +125,6 @@ void canOnlyUsePublicFactoryMethods() {
112125
.withMessageContaining("Cannot manufacture class")
113126
.withNoCause();
114127
}
115-
116128
@Test
117129
@DisplayName("method arguments are used")
118130
void factoryMethodWithArgument() {
@@ -122,6 +134,16 @@ void factoryMethodWithArgument() {
122134

123135
assertThat(result.getValue()).isNotNull();
124136
}
137+
@Test
138+
@DisplayName("optional can be created (and may be empty)")
139+
void createOptional() {
140+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
141+
142+
var result = sut.manufacture(new SpecimenType<Optional<String>>(){});
143+
144+
assertThat(result).isInstanceOf(Optional.class);
145+
assertThat(result.orElse("optional may be empty")).isInstanceOf(String.class);
146+
}
125147

126148
@Test
127149
@DisplayName("method without arguments is used")
@@ -132,17 +154,27 @@ void factoryMethodWithoutArgument() {
132154

133155
assertThat(result.getValue()).isEqualTo(42);
134156
}
135-
136157
@Test
137158
@DisplayName("method with generic arguments is used")
138159
void factoryMethodWithGenericArgument() {
139160
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
140161

141-
FactoryMethodWithGenericArgument result = sut.manufacture(new SpecimenType<FactoryMethodWithGenericArgument<Integer>>() {});
162+
var result = sut.manufacture(new SpecimenType<FactoryMethodWithGenericArgument<Integer>>() {});
142163

143164
assertThat(result.getValue()).isNotNull();
144165
}
145166

167+
@Test
168+
@DisplayName("method without arguments is used")
169+
void genericNoArgumentFactoryMethod() {
170+
var sut = new InstanceFactory(new SpecimenFactory(new Context(Configuration.configure())));
171+
172+
var result = sut.manufacture(new SpecimenType<GenericClassWithFactoryMethodWithoutArgument<Integer>>() {});
173+
174+
assertThat(result).isNotNull();
175+
assertThat(result.getValue()).isEqualTo(42);
176+
}
177+
146178
}
147179

148180
@Nested

src/test/java/com/github/nylle/javafixture/annotations/fixture/JavaFixtureClassExtensionTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ void injectParameterViaClassExtension(Contract contract, int intValue, Optional<
2424
assertThat(contract.getId()).isBetween(Long.MIN_VALUE, Long.MAX_VALUE);
2525
assertThat(intValue).isBetween(Integer.MIN_VALUE, Integer.MAX_VALUE);
2626
assertThat(optionalString).isInstanceOf(Optional.class);
27-
assertThat(optionalString).isPresent();
28-
assertThat(optionalString.get()).isInstanceOf(String.class);
2927
}
3028

3129
@FixturedTest

src/test/java/com/github/nylle/javafixture/annotations/fixture/TestWithFixtureTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ void injectParameterViaMethodExtension(Contract contract, int intValue, Optional
2020
assertThat(contract.getId()).isBetween(Long.MIN_VALUE, Long.MAX_VALUE);
2121
assertThat(intValue).isBetween(Integer.MIN_VALUE, Integer.MAX_VALUE);
2222
assertThat(optionalString).isInstanceOf(Optional.class);
23-
assertThat(optionalString).isPresent();
24-
assertThat(optionalString.get()).isInstanceOf(String.class);
2523
}
2624

2725
@TestWithFixture(minCollectionSize = 11, maxCollectionSize = 11, positiveNumbersOnly = true)

src/test/java/com/github/nylle/javafixture/specimen/GenericSpecimenTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ void createGeneric() {
102102
void subSpecimenAreProperlyCached() {
103103
var result = new GenericSpecimen<>(new SpecimenType<TestObjectGeneric<Optional<String>, Optional<Integer>>>(){}, context, specimenFactory).create(new Annotation[0]);
104104

105-
assertThat(result.getT().get()).isInstanceOf(String.class);
106-
assertThat(result.getU().get()).isInstanceOf(Integer.class);
105+
assertThat(result.getT()).isInstanceOf(Optional.class);
106+
assertThat(result.getU()).isInstanceOf(Optional.class);
107107
}
108108

109109
@Test

src/test/java/com/github/nylle/javafixture/testobjects/factorymethod/FactoryMethodWithGenericArgument.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ private FactoryMethodWithGenericArgument(T value) {
99
}
1010

1111
public static <T> FactoryMethodWithGenericArgument<T> factoryMethod(T value) {
12-
return new FactoryMethodWithGenericArgument(value);
12+
return new FactoryMethodWithGenericArgument(42);
1313
}
1414

1515
public T getValue() {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.github.nylle.javafixture.testobjects.factorymethod;
2+
3+
public class GenericClassWithFactoryMethodWithoutArgument<T> {
4+
5+
private T value;
6+
7+
private GenericClassWithFactoryMethodWithoutArgument(T value) {
8+
this.value = value;
9+
}
10+
11+
public static <T> GenericClassWithFactoryMethodWithoutArgument<T> factoryMethod() {
12+
return new GenericClassWithFactoryMethodWithoutArgument(42);
13+
}
14+
15+
public T getValue() {
16+
return value;
17+
}
18+
}

0 commit comments

Comments
 (0)