Skip to content

Commit

Permalink
Add compatibility with ObjectPropertyGenerator and CandidateConcreteP…
Browse files Browse the repository at this point in the history
…ropertyResolver (#1012)
  • Loading branch information
seongahjo authored Jul 27, 2024
1 parent 6501f40 commit dbf39ee
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ public ArbitraryProperty(
ObjectProperty objectProperty,
boolean container,
double nullInject,
Map<Property, List<Property>> childPropertyListsByCandidateProperty
List<ConcreteTypeDefinition> concreteTypeDefinitions
) {
this.objectProperty = objectProperty;
this.container = container;
this.nullInject = nullInject;
this.concreteTypeDefinitions = toConcreteTypeDefinition(childPropertyListsByCandidateProperty);
this.concreteTypeDefinitions = concreteTypeDefinitions;
}

public ObjectProperty getObjectProperty() {
Expand All @@ -70,7 +70,12 @@ public boolean isContainer() {
}

public ArbitraryProperty withNullInject(double nullInject) {
return new ArbitraryProperty(this.objectProperty.withNullInject(nullInject), this.container);
return new ArbitraryProperty(
this.objectProperty,
this.container,
nullInject,
this.concreteTypeDefinitions
);
}

public double getNullInject() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@

package com.navercorp.fixturemonkey.api.generator;

import java.util.Collections;
import java.util.List;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;

import com.navercorp.fixturemonkey.api.property.Property;
import com.navercorp.fixturemonkey.api.property.PropertyGenerator;

@API(since = "0.4.0", status = Status.MAINTAINED)
public final class DefaultObjectPropertyGenerator implements ObjectPropertyGenerator {
Expand All @@ -35,16 +31,11 @@ public final class DefaultObjectPropertyGenerator implements ObjectPropertyGener
@Override
public ObjectProperty generate(ObjectPropertyGeneratorContext context) {
Property property = context.getProperty();
PropertyGenerator propertyGenerator = context.getPropertyGenerator();
List<Property> childProperties = propertyGenerator.generateChildProperties(property);
double nullInject = context.getNullInjectGenerator().generate(context);

return new ObjectProperty(
property,
context.getPropertyNameResolver(),
nullInject,
context.getElementIndex(),
Collections.singletonMap(property, childProperties)
context.getElementIndex()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package com.navercorp.fixturemonkey.api.generator;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -40,14 +41,18 @@ public final class ObjectProperty {
private final PropertyNameResolver propertyNameResolver;

@Deprecated
private final double nullInject;
private final Double nullInject;

@Nullable
private final Integer elementIndex;

@Deprecated
private final Map<Property, List<Property>> childPropertyListsByCandidateProperty;

/**
* Use {@link ObjectProperty(Property, PropertyNameResolver, Integer)} instead.
*/
@Deprecated
public ObjectProperty(
Property property,
PropertyNameResolver propertyNameResolver,
Expand All @@ -62,6 +67,18 @@ public ObjectProperty(
this.childPropertyListsByCandidateProperty = childPropertyListsByCandidateProperty;
}

public ObjectProperty(
Property property,
PropertyNameResolver propertyNameResolver,
@Nullable Integer elementIndex
) {
this.property = property;
this.propertyNameResolver = propertyNameResolver;
this.elementIndex = elementIndex;
this.nullInject = null;
this.childPropertyListsByCandidateProperty = Collections.emptyMap();
}

public Property getProperty() {
return this.property;
}
Expand All @@ -75,7 +92,8 @@ public String getResolvedPropertyName() {
}

@Deprecated
public double getNullInject() {
@Nullable
public Double getNullInject() {
return this.nullInject;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,11 +474,31 @@ private static List<MatcherOperator<ContainerPropertyGenerator>> getDefaultConta
}

private static List<MatcherOperator<PropertyGenerator>> getDefaultPropertyGenerators() {
return Collections.singletonList(
return Arrays.asList(
new MatcherOperator<>(ConstantIntrospector.INSTANCE, EmptyPropertyGenerator.INSTANCE),
new MatcherOperator<>(
property -> {
Class<?> actualType = Types.getActualType(property.getType());
return actualType.isPrimitive()
|| DEFAULT_JAVA_PACKAGES.stream()
.anyMatch(actualType.getPackage().getName()::startsWith);
},
EmptyPropertyGenerator.INSTANCE
),
new MatcherOperator<>(Matchers.ENUM_TYPE_MATCHER, EmptyPropertyGenerator.INSTANCE),
new MatcherOperator<>(
p -> Modifier.isInterface(Types.getActualType(p.getType()).getModifiers()),
new NoArgumentInterfaceJavaMethodPropertyGenerator()
)
);
}

private static class EmptyPropertyGenerator implements PropertyGenerator {
private static final PropertyGenerator INSTANCE = new EmptyPropertyGenerator();

@Override
public List<Property> generateChildProperties(Property property) {
return Collections.emptyList();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,23 @@
import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;

import com.navercorp.fixturemonkey.api.generator.InterfaceObjectPropertyGenerator;
import com.navercorp.fixturemonkey.api.generator.ObjectPropertyGenerator;
import com.navercorp.fixturemonkey.api.introspector.AnonymousArbitraryIntrospector;
import com.navercorp.fixturemonkey.api.introspector.MatchArbitraryIntrospector;
import com.navercorp.fixturemonkey.api.matcher.ExactTypeMatcher;
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.property.CandidateConcretePropertyResolver;
import com.navercorp.fixturemonkey.api.property.ConcreteTypeCandidateConcretePropertyResolver;
import com.navercorp.fixturemonkey.api.type.Types;

/**
* This plugin is used to extend an interface.
*/
@API(since = "1.0.6", status = Status.EXPERIMENTAL)
public final class InterfacePlugin implements Plugin {
private final List<MatcherOperator<ObjectPropertyGenerator>> objectPropertyGenerators = new ArrayList<>();
private final List<MatcherOperator<CandidateConcretePropertyResolver>> candidateConcretePropertyResolvers =
new ArrayList<>();
private boolean useAnonymousArbitraryIntrospector = true;

/**
Expand Down Expand Up @@ -83,10 +84,10 @@ public <T> InterfacePlugin interfaceImplements(
Matcher matcher,
List<Class<? extends T>> implementations
) {
this.objectPropertyGenerators.add(
this.candidateConcretePropertyResolvers.add(
new MatcherOperator<>(
matcher.intersect(p -> Modifier.isInterface(Types.getActualType(p.getType()).getModifiers())),
new InterfaceObjectPropertyGenerator<>(implementations)
new ConcreteTypeCandidateConcretePropertyResolver<>(implementations)
)
);

Expand Down Expand Up @@ -132,29 +133,16 @@ public <T> InterfacePlugin abstractClassExtends(
Matcher matcher,
List<Class<? extends T>> implementations
) {
this.objectPropertyGenerators.add(
this.candidateConcretePropertyResolvers.add(
new MatcherOperator<>(
matcher.intersect(p -> Modifier.isAbstract(Types.getActualType(p.getType()).getModifiers())),
new InterfaceObjectPropertyGenerator<>(implementations)
new ConcreteTypeCandidateConcretePropertyResolver<>(implementations)
)
);

return this;
}

/**
* Registers an interface implementation with a specified matcher.
* This method facilitates adding custom implementations for interfaces using a matcher.
*
* @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;
}

/**
* Configures the use of an anonymous arbitrary introspector.
* By default, this option is enabled (default value is true).
Expand All @@ -171,8 +159,8 @@ public InterfacePlugin useAnonymousArbitraryIntrospector(boolean useAnonymousArb

@Override
public void accept(FixtureMonkeyOptionsBuilder optionsBuilder) {
for (MatcherOperator<ObjectPropertyGenerator> objectPropertyGenerator : objectPropertyGenerators) {
optionsBuilder.insertFirstArbitraryObjectPropertyGenerator(objectPropertyGenerator);
for (MatcherOperator<CandidateConcretePropertyResolver> resolver : candidateConcretePropertyResolvers) {
optionsBuilder.insertFirstCandidateConcretePropertyResolvers(resolver);
}

if (useAnonymousArbitraryIntrospector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
package com.navercorp.fixturemonkey.tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Nullable;

Expand All @@ -44,6 +44,7 @@
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptions;
import com.navercorp.fixturemonkey.api.property.CandidateConcretePropertyResolver;
import com.navercorp.fixturemonkey.api.property.ConcreteTypeDefinition;
import com.navercorp.fixturemonkey.api.property.DefaultCandidateConcretePropertyResolver;
import com.navercorp.fixturemonkey.api.property.MapEntryElementProperty;
import com.navercorp.fixturemonkey.api.property.Property;
Expand Down Expand Up @@ -118,7 +119,7 @@ private ObjectNode generateObjectNode(

ObjectProperty objectProperty = objectPropertyGenerator.generate(objectPropertyGeneratorContext);

Map<Property, List<Property>> childPropertyListsByCandidateProperty;
List<ConcreteTypeDefinition> concreteTypeDefinitions;
ContainerInfoManipulator appliedContainerInfoManipulator = null;
if (container) {
List<ObjectProperty> objectProperties =
Expand All @@ -144,32 +145,58 @@ private ObjectNode generateObjectNode(
);

List<Property> candidateProperties = resolveCandidateProperties(property);
childPropertyListsByCandidateProperty = candidateProperties.stream()
.collect(
Collectors.toMap(
Function.identity(),
it -> childContainerProperty.getElementProperties()
)
);
concreteTypeDefinitions = candidateProperties.stream()
.map(it -> new ConcreteTypeDefinition(it, childContainerProperty.getElementProperties()))
.collect(Collectors.toList());
} else {
childPropertyListsByCandidateProperty = objectProperty.getChildPropertyListsByCandidateProperty();
List<ConcreteTypeDefinition> objectPropertyCandidateTypeDefinitions =
objectProperty.getChildPropertyListsByCandidateProperty().entrySet().stream()
.map(it -> new ConcreteTypeDefinition(it.getKey(), it.getValue()))
.collect(Collectors.toList());

CandidateConcretePropertyResolver candidateConcretePropertyResolver =
fixtureMonkeyOptions.getCandidateConcretePropertyResolver(property);

// TODO: It is there for compatibility. It will be removed in 1.1.0.
if (candidateConcretePropertyResolver == null && objectPropertyCandidateTypeDefinitions.isEmpty()) {
candidateConcretePropertyResolver = DefaultCandidateConcretePropertyResolver.INSTANCE;
}

List<ConcreteTypeDefinition> optionCandidateTypeDefinitions = Collections.emptyList();
if (candidateConcretePropertyResolver != null) {
List<Property> candidateProperties = candidateConcretePropertyResolver.resolve(property);
optionCandidateTypeDefinitions = candidateProperties.stream()
.map(it ->
new ConcreteTypeDefinition(
it,
getPropertyGenerator(context.getPropertyConfigurers()).generateChildProperties(it)
)
)
.collect(Collectors.toList());
}

concreteTypeDefinitions =
Stream.concat(objectPropertyCandidateTypeDefinitions.stream(), optionCandidateTypeDefinitions.stream())
.collect(Collectors.toList());
}

double nullInject = objectProperty.getNullInject() != null
? objectProperty.getNullInject()
: fixtureMonkeyOptions.getNullInjectGenerator(property).generate(objectPropertyGeneratorContext);

ArbitraryProperty arbitraryProperty = new ArbitraryProperty(
objectProperty,
container,
objectProperty.getNullInject(),
childPropertyListsByCandidateProperty
nullInject,
concreteTypeDefinitions
);

TraverseContext nextTraverseContext = context.appendArbitraryProperty(arbitraryProperty);

List<ObjectNode> children = new ArrayList<>();
for (
Entry<Property, List<Property>> childPropertiesByCandidateProperty :
childPropertyListsByCandidateProperty.entrySet()
) {
List<Property> childProperties = childPropertiesByCandidateProperty.getValue();
Property candidateProperty = childPropertiesByCandidateProperty.getKey();
for (ConcreteTypeDefinition concreteTypeDefinition : concreteTypeDefinitions) {
List<Property> childProperties = concreteTypeDefinition.getChildPropertyLists();
Property candidateProperty = concreteTypeDefinition.getConcreteProperty();

children.addAll(
generateChildrenNodes(
Expand All @@ -180,8 +207,9 @@ private ObjectNode generateObjectNode(
);
}

Property resolvedProperty = new ArrayList<>(childPropertyListsByCandidateProperty.keySet())
.get(Randoms.nextInt(childPropertyListsByCandidateProperty.size()));
Property resolvedProperty = concreteTypeDefinitions
.get(Randoms.nextInt(concreteTypeDefinitions.size()))
.getConcreteProperty();

ObjectNode objectNode = new ObjectNode(
resolvedParentProperty,
Expand Down

0 comments on commit dbf39ee

Please sign in to comment.