diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/plugin/InterfacePlugin.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/plugin/InterfacePlugin.java index 6d3acff72e..e7eb630356 100644 --- a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/plugin/InterfacePlugin.java +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/plugin/InterfacePlugin.java @@ -83,11 +83,27 @@ public InterfacePlugin interfaceImplements( public InterfacePlugin interfaceImplements( Matcher matcher, List> implementations + ) { + return this.interfaceImplements(matcher, new ConcreteTypeCandidateConcretePropertyResolver<>(implementations)); + } + + /** + * Registers an interface implementation with a specified matcher. + * This method facilitates adding custom implementations for interfaces using a matcher. + * + * @param matcher the matcher to be used for matching interfaces + * @param concretePropertyResolver the resolver to resolve the concrete properties + * @return the InterfacePlugin instance for fluent chaining + * @throws IllegalArgumentException if the first parameter is not an interface + */ + public InterfacePlugin interfaceImplements( + Matcher matcher, + CandidateConcretePropertyResolver concretePropertyResolver ) { this.candidateConcretePropertyResolvers.add( new MatcherOperator<>( matcher.intersect(p -> Modifier.isInterface(Types.getActualType(p.getType()).getModifiers())), - new ConcreteTypeCandidateConcretePropertyResolver<>(implementations) + concretePropertyResolver ) ); @@ -132,11 +148,27 @@ public InterfacePlugin abstractClassExtends( public InterfacePlugin abstractClassExtends( Matcher matcher, List> implementations + ) { + return this.abstractClassExtends(matcher, new ConcreteTypeCandidateConcretePropertyResolver<>(implementations)); + } + + /** + * Registers an abstract class implementation with a specified matcher. + * This method facilitates adding custom implementations for interfaces using a matcher. + * + * @param matcher the matcher to be used for matching abstract class + * @param concretePropertyResolver the resolver to resolve the concrete properties + * @return the InterfacePlugin instance for fluent chaining + * @throws IllegalArgumentException if the first parameter is not an abstract class + */ + public InterfacePlugin abstractClassExtends( + Matcher matcher, + CandidateConcretePropertyResolver concretePropertyResolver ) { this.candidateConcretePropertyResolvers.add( new MatcherOperator<>( matcher.intersect(p -> Modifier.isAbstract(Types.getActualType(p.getType()).getModifiers())), - new ConcreteTypeCandidateConcretePropertyResolver<>(implementations) + concretePropertyResolver ) ); diff --git a/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt b/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt index 2196e7f842..c59b74d762 100644 --- a/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt +++ b/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt @@ -33,7 +33,11 @@ import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntr import com.navercorp.fixturemonkey.api.matcher.AssignableTypeMatcher import com.navercorp.fixturemonkey.api.matcher.MatcherOperator import com.navercorp.fixturemonkey.api.plugin.InterfacePlugin +import com.navercorp.fixturemonkey.api.property.CandidateConcretePropertyResolver import com.navercorp.fixturemonkey.api.property.ConcreteTypeCandidateConcretePropertyResolver +import com.navercorp.fixturemonkey.api.property.Property +import com.navercorp.fixturemonkey.api.property.PropertyUtils +import com.navercorp.fixturemonkey.api.type.Types import com.navercorp.fixturemonkey.api.type.Types.GeneratingWildcardType import com.navercorp.fixturemonkey.customizer.Values import com.navercorp.fixturemonkey.kotlin.KotlinPlugin @@ -889,6 +893,70 @@ class KotlinTest { then(actual).isInstanceOf(ArrayList::class.java) } + @Test + fun complexAbstractExtendsReturnsFirst() { + abstract class ParentAbstractClass + + abstract class FirstAbstractClass : ParentAbstractClass() + abstract class SecondAbstractClass : ParentAbstractClass() + + class FirstConcreteClass : FirstAbstractClass() + class SecondConcreteClass : SecondAbstractClass() + + val sut = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .plugin( + InterfacePlugin() + .abstractClassExtends( + AssignableTypeMatcher(ParentAbstractClass::class.java) + ) { property -> + when (property.type) { + FirstAbstractClass::class.java -> listOf(PropertyUtils.toProperty(FirstConcreteClass::class.java)) + SecondAbstractClass::class.java -> listOf(PropertyUtils.toProperty(SecondConcreteClass::class.java)) + else -> throw NotImplementedError() + } + } + + ) + .build() + + val actual: FirstAbstractClass = sut.giveMeOne() + + then(actual).isInstanceOf(FirstConcreteClass::class.java) + } + + @Test + fun complexAbstractExtendsReturnsSecond() { + abstract class ParentAbstractClass + + abstract class FirstAbstractClass : ParentAbstractClass() + abstract class SecondAbstractClass : ParentAbstractClass() + + class FirstConcreteClass : FirstAbstractClass() + class SecondConcreteClass : SecondAbstractClass() + + val sut = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .plugin( + InterfacePlugin() + .abstractClassExtends( + AssignableTypeMatcher(ParentAbstractClass::class.java) + ) { property -> + when (property.type) { + FirstAbstractClass::class.java -> listOf(PropertyUtils.toProperty(FirstConcreteClass::class.java)) + SecondAbstractClass::class.java -> listOf(PropertyUtils.toProperty(SecondConcreteClass::class.java)) + else -> throw NotImplementedError() + } + } + + ) + .build() + + val actual: SecondAbstractClass = sut.giveMeOne() + + then(actual).isInstanceOf(SecondConcreteClass::class.java) + } + companion object { private val SUT: FixtureMonkey = FixtureMonkey.builder() .plugin(KotlinPlugin())