Skip to content

Commit

Permalink
Add InterfacePlugin supports abstract classes through abstractClassEx…
Browse files Browse the repository at this point in the history
…tends option (#892)
  • Loading branch information
seongahjo authored Jan 23, 2024
1 parent 1f610cb commit 3858926
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 32 deletions.
8 changes: 8 additions & 0 deletions docs/content/v1.0.x/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ menu:
docs:
weight: 100
---
sectionStart
### v.1.0.13
Add InterfacePlugin supports abstract classes through `abstractClassExtends` option.

sectionEnd

sectionStart

sectionStart
### v.1.0.12
Fix generating an object with the value class property.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.navercorp.fixturemonkey.api.matcher.Matcher;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptionsBuilder;
import com.navercorp.fixturemonkey.api.type.Types;

/**
* This plugin is used to extend an interface.
Expand All @@ -43,49 +44,102 @@ public final class InterfacePlugin implements Plugin {
private final List<MatcherOperator<ObjectPropertyGenerator>> objectPropertyGenerators = new ArrayList<>();
private boolean useAnonymousArbitraryIntrospector = true;

/**
* Registers implementations for a given interface.
* This method validates that the provided class is an interface.
* It throws an IllegalArgumentException if the validation fails.
*
* @param <T> the type parameter of the interface
* @param interfaceType the interface class to be implemented
* @param implementations a list of classes implementing the interface
* @return the InterfacePlugin instance for fluent chaining
* @throws IllegalArgumentException if the first parameter is not an interface
*/
public <T> InterfacePlugin interfaceImplements(
Class<T> interfaceType,
List<Class<? extends T>> implementations
) {
if (!Modifier.isInterface(interfaceType.getModifiers())) {
throw new IllegalArgumentException(
"interfaceImplements option first parameter should be interface. "
+ interfaceType.getTypeName()
);
}

return interfaceImplements(new ExactTypeMatcher(interfaceType), implementations);
}

/**
* Registers an interface implementation with a specified matcher.
* This method facilitates adding custom implementations for interfaces using a matcher.
*
* @param <T> the type parameter of the interface
* @param matcher the matcher to be used for matching interfaces
* @param <T> the type parameter of the interface
* @param matcher the matcher to be used for matching interfaces
* @param implementations a list of classes implementing the interface
* @return the InterfacePlugin instance for fluent chaining
* @throws IllegalArgumentException if the first parameter is not an interface
*/
public <T> InterfacePlugin interfaceImplements(
Matcher matcher,
List<Class<? extends T>> implementations
) {
return interfaceImplements(
this.objectPropertyGenerators.add(
new MatcherOperator<>(
matcher,
new InterfaceObjectPropertyGenerator<>(implementations))
matcher.intersect(p -> Modifier.isInterface(Types.getActualType(p.getType()).getModifiers())),
new InterfaceObjectPropertyGenerator<>(implementations)
)
);

return this;
}

/**
* Registers implementations for a given interface.
* This method validates that the provided class is an interface.
* Registers implementations for a given abstract class.
* This method validates that the provided class is an abstract class.
* It throws an IllegalArgumentException if the validation fails.
*
* @param <T> the type parameter of the interface
* @param interfaceClass the interface class to be implemented
* @param implementations a list of classes implementing the interface
* @param <T> the type parameter of the interface
* @param abstractClassType the abstract class type to be implemented
* @param implementations a list of classes implementing the abstract class
* @return the InterfacePlugin instance for fluent chaining
* @throws IllegalArgumentException if the first parameter is not an interface
* @throws IllegalArgumentException if the first parameter is not an abstract class
*/
public <T> InterfacePlugin interfaceImplements(
Class<T> interfaceClass,
public <T> InterfacePlugin abstractClassExtends(
Class<T> abstractClassType,
List<Class<? extends T>> implementations
) {
if (!Modifier.isInterface(interfaceClass.getModifiers())) {
if (!Modifier.isAbstract(abstractClassType.getModifiers())) {
throw new IllegalArgumentException(
"interfaceImplements option first parameter should be interface. "
+ interfaceClass.getTypeName()
"abstractClassExtends option first parameter should be abstract class. "
+ abstractClassType.getTypeName()
);
}

return interfaceImplements(new ExactTypeMatcher(interfaceClass), implementations);
return abstractClassExtends(new ExactTypeMatcher(abstractClassType), implementations);
}

/**
* Registers an abstract class implementation with a specified matcher.
* This method facilitates adding custom implementations for interfaces using a matcher.
*
* @param <T> the type parameter of the abstract class
* @param matcher the matcher to be used for matching abstract class
* @param implementations a list of classes implementing the abstract class
* @return the InterfacePlugin instance for fluent chaining
* @throws IllegalArgumentException if the first parameter is not an abstract class
*/
public <T> InterfacePlugin abstractClassExtends(
Matcher matcher,
List<Class<? extends T>> implementations
) {
this.objectPropertyGenerators.add(
new MatcherOperator<>(
matcher.intersect(p -> Modifier.isAbstract(Types.getActualType(p.getType()).getModifiers())),
new InterfaceObjectPropertyGenerator<>(implementations)
)
);

return this;
}

/**
Expand All @@ -95,6 +149,7 @@ public <T> InterfacePlugin interfaceImplements(
* @param objectPropertyGenerator the object property generator to add
* @return the InterfacePlugin instance for fluent chaining
*/
@Deprecated
public InterfacePlugin interfaceImplements(MatcherOperator<ObjectPropertyGenerator> objectPropertyGenerator) {
this.objectPropertyGenerators.add(objectPropertyGenerator);
return this;
Expand All @@ -106,7 +161,7 @@ public InterfacePlugin interfaceImplements(MatcherOperator<ObjectPropertyGenerat
* When enabled, it uses an instance of {@link AnonymousArbitraryIntrospector} as the fallback introspector.
*
* @param useAnonymousArbitraryIntrospector a boolean flag to enable (true) or disable (false)
* the anonymous arbitrary introspector. Default value is true.
* the anonymous arbitrary introspector. Default value is true.
* @return the InterfacePlugin instance for fluent chaining
*/
public InterfacePlugin useAnonymousArbitraryIntrospector(boolean useAnonymousArbitraryIntrospector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import net.jqwik.api.Example;

import com.navercorp.fixturemonkey.FixtureMonkey;
import com.navercorp.fixturemonkey.api.plugin.InterfacePlugin;
import com.navercorp.fixturemonkey.mockito.plugin.MockitoPluginTestSpecs.AbstractSample;
import com.navercorp.fixturemonkey.mockito.plugin.MockitoPluginTestSpecs.AbstractSampleImpl;
import com.navercorp.fixturemonkey.mockito.plugin.MockitoPluginTestSpecs.InterfaceSample;
Expand Down Expand Up @@ -76,7 +77,10 @@ void interfaceImplementsAndMockitoAbstract() {
FixtureMonkey sut = FixtureMonkey.builder()
.plugin(new MockitoPlugin())
.defaultNullInjectGenerator(context -> 0)
.interfaceImplements(AbstractSample.class, Collections.singletonList(AbstractSampleImpl.class))
.plugin(
new InterfacePlugin()
.abstractClassExtends(AbstractSample.class, Collections.singletonList(AbstractSampleImpl.class))
)
.build();

String actual = sut.giveMeOne(Sample.class).getAbstractSample().getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.navercorp.fixturemonkey.api.generator.ArbitraryContainerInfoGenerator;
import com.navercorp.fixturemonkey.api.generator.ArbitraryGenerator;
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGenerator;
import com.navercorp.fixturemonkey.api.generator.InterfaceObjectPropertyGenerator;
import com.navercorp.fixturemonkey.api.generator.NullInjectGenerator;
import com.navercorp.fixturemonkey.api.generator.ObjectPropertyGenerator;
import com.navercorp.fixturemonkey.api.introspector.ArbitraryIntrospector;
Expand Down Expand Up @@ -454,7 +455,9 @@ public <T> FixtureMonkeyBuilder interfaceImplements(
Matcher matcher,
List<Class<? extends T>> implementations
) {
defaultInterfacePlugin.interfaceImplements(matcher, implementations);
this.pushObjectPropertyGenerator(
new MatcherOperator<>(matcher, new InterfaceObjectPropertyGenerator<>(implementations))
);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin;
import com.navercorp.fixturemonkey.api.matcher.ExactTypeMatcher;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.plugin.InterfacePlugin;
import com.navercorp.fixturemonkey.api.type.TypeReference;
import com.navercorp.fixturemonkey.api.type.Types;
import com.navercorp.fixturemonkey.test.FixtureMonkeyOptionsAdditionalTestSpecs.AbstractNoneConcreteIntValue;
Expand Down Expand Up @@ -1341,9 +1342,12 @@ void sampleInterfaceChildWhenOptionHasHierarchy() {
@Property
void sampleConcreteWhenHasSameNameProperty() {
FixtureMonkey sut = FixtureMonkey.builder()
.interfaceImplements(
AbstractSamePropertyValue.class,
Collections.singletonList(ConcreteSamePropertyValue.class)
.plugin(
new InterfacePlugin()
.abstractClassExtends(
AbstractSamePropertyValue.class,
Collections.singletonList(ConcreteSamePropertyValue.class)
)
)
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();
Expand All @@ -1361,7 +1365,10 @@ void setConcreteListWithNoParentValue() {
implementations.add(AbstractNoneConcreteIntValue.class);

FixtureMonkey sut = FixtureMonkey.builder()
.interfaceImplements(AbstractNoneValue.class, implementations)
.plugin(
new InterfacePlugin()
.abstractClassExtends(AbstractNoneValue.class, implementations)
)
.build();

AbstractNoneConcreteStringValue abstractNoneConcreteStringValue = new AbstractNoneConcreteStringValue();
Expand All @@ -1385,7 +1392,10 @@ void setConcreteListWithNoParentValue() {
void setConcreteClassWhenHasParentValue() {
// given
FixtureMonkey sut = FixtureMonkey.builder()
.interfaceImplements(AbstractValue.class, Collections.singletonList(ConcreteStringValue.class))
.plugin(
new InterfacePlugin()
.abstractClassExtends(AbstractValue.class, Collections.singletonList(ConcreteStringValue.class))
)
.build();

ConcreteStringValue expected = new ConcreteStringValue();
Expand All @@ -1404,9 +1414,12 @@ void setConcreteClassWhenHasParentValue() {
void setConcreteClassWhenHasNoParentValue() {
// given
FixtureMonkey sut = FixtureMonkey.builder()
.interfaceImplements(
AbstractNoneValue.class,
Collections.singletonList(AbstractNoneConcreteStringValue.class)
.plugin(
new InterfacePlugin()
.abstractClassExtends(
AbstractNoneValue.class,
Collections.singletonList(AbstractNoneConcreteStringValue.class)
)
)
.build();

Expand All @@ -1430,7 +1443,10 @@ void setConcreteList() {
implementations.add(ConcreteIntValue.class);

FixtureMonkey sut = FixtureMonkey.builder()
.interfaceImplements(AbstractValue.class, implementations)
.plugin(
new InterfacePlugin()
.abstractClassExtends(AbstractValue.class, implementations)
)
.build();

ConcreteStringValue concreteStringValue = new ConcreteStringValue();
Expand All @@ -1455,9 +1471,12 @@ void setConcreteList() {
@Property
void sampleSelfRecursiveAbstract() {
FixtureMonkey sut = FixtureMonkey.builder()
.interfaceImplements(
SelfRecursiveAbstractValue.class,
Collections.singletonList(SelfRecursiveImplementationValue.class)
.plugin(
new InterfacePlugin()
.abstractClassExtends(
SelfRecursiveAbstractValue.class,
Collections.singletonList(SelfRecursiveImplementationValue.class)
)
)
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();
Expand Down

0 comments on commit 3858926

Please sign in to comment.