Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add InterfacePlugin supports abstract class #892

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading