Skip to content

Commit

Permalink
Add forceExpand for specific TypeDefinition (#1129)
Browse files Browse the repository at this point in the history
  • Loading branch information
seongahjo authored Dec 28, 2024
1 parent f3d1411 commit be0258a
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ public final class ContainerPropertyGeneratorContext {
private final Property property;
@Nullable
private final ArbitraryContainerInfo containerInfo;
@Nullable
private final ArbitraryContainerInfoGenerator containerInfoGenerator;

public ContainerPropertyGeneratorContext(
Property property,
@Nullable ArbitraryContainerInfo containerInfo,
ArbitraryContainerInfoGenerator containerInfoGenerator
@Nullable ArbitraryContainerInfoGenerator containerInfoGenerator
) {
this.property = property;
this.containerInfo = containerInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public LazyArbitrary<PropertyPath> getLazyPropertyPath() {

@Override
public boolean expand() {
if (this.expandedTypeDefinition == resolvedTypeDefinition) {
if (this.expandedTypeDefinition != null) {
return false;
}

Expand Down Expand Up @@ -268,6 +268,27 @@ public void forceExpand() {
this.expandedTypeDefinition = resolvedTypeDefinition;
}

@Override
public void forceExpand(TypeDefinition typeDefinition) {
List<TraverseNode> children;
if (this.getTreeProperty().isContainer()) {
children = this.expandContainerNode(
typeDefinition,
traverseContext.withParentProperties()
).collect(Collectors.toList());
} else {
children = this.generateChildrenNodes(
typeDefinition.getResolvedProperty(),
typeDefinition.getPropertyGenerator()
.generateChildProperties(typeDefinition.getResolvedProperty()),
this.nullInject,
traverseContext.withParentProperties()
);
}
this.setMergedChildren(children);
this.expandedTypeDefinition = typeDefinition;
}

@Override
public TraverseNodeMetadata getMetadata() {
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ public interface TraverseNode {
*/
void forceExpand();

/**
* expands the {@link TraverseNode} forcibly. In result, it always generates the child {@link TraverseNode}s.
* It generates the child {@link TraverseNode}s by given {@link TypeDefinition}.
* {@code Force} means that it expands as if it were a root node, even if it is not.
* Unlike {@link #expand()}, it expands without metadata generated on expanding of the parent {@link TraverseNode}.
* <p>
* The child nodes are always generated by the given {@link TypeDefinition} unlike {@link #forceExpand()}.
* <p>
* The leaf {@link TraverseNode} may generate child {@link TraverseNode}s.
* For example, the {@link TraverseNode} with a self-reference.
*
* @param typeDefinition the {@link TypeDefinition} to expand forcibly
*/
void forceExpand(TypeDefinition typeDefinition);

/**
* retrieves the metadata to traverse the tree. Some of its properties can be mutated during traversal.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,7 @@ class KotlinTest {
then(actual).isEqualTo(expected)
}

@Test
@RepeatedTest(TEST_COUNT)
fun register() {
class NestedInnerObject(val list: List<String>)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ public FixtureMonkey build() {
MonkeyManipulatorFactory monkeyManipulatorFactory = new MonkeyManipulatorFactory(
new AtomicInteger(),
monkeyExpressionFactory,
fixtureMonkeyOptions.getDecomposedContainerValueFactory()
fixtureMonkeyOptions.getDecomposedContainerValueFactory(),
fixtureMonkeyOptions.getContainerPropertyGenerators()
);

Randoms.setSeed(seed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary;
import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory;
import com.navercorp.fixturemonkey.api.generator.ArbitraryContainerInfo;
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGenerator;
import com.navercorp.fixturemonkey.api.lazy.LazyArbitrary;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.property.Property;
Expand All @@ -60,15 +61,18 @@ public final class MonkeyManipulatorFactory {
private final AtomicInteger sequence;
private final MonkeyExpressionFactory monkeyExpressionFactory;
private final DecomposedContainerValueFactory decomposedContainerValueFactory;
private final List<MatcherOperator<ContainerPropertyGenerator>> containerPropertyGenerators;

public MonkeyManipulatorFactory(
AtomicInteger sequence,
MonkeyExpressionFactory monkeyExpressionFactory,
DecomposedContainerValueFactory decomposedContainerValueFactory
DecomposedContainerValueFactory decomposedContainerValueFactory,
List<MatcherOperator<ContainerPropertyGenerator>> containerPropertyGenerators
) {
this.sequence = sequence;
this.monkeyExpressionFactory = monkeyExpressionFactory;
this.decomposedContainerValueFactory = decomposedContainerValueFactory;
this.containerPropertyGenerators = containerPropertyGenerators;
}

public ArbitraryManipulator newArbitraryManipulator(
Expand Down Expand Up @@ -239,7 +243,8 @@ public MonkeyManipulatorFactory copy() {
return new MonkeyManipulatorFactory(
new AtomicInteger(sequence.get()),
monkeyExpressionFactory,
decomposedContainerValueFactory
decomposedContainerValueFactory,
containerPropertyGenerators
);
}

Expand All @@ -259,24 +264,28 @@ private NodeManipulator convertToNodeManipulator(int sequence, @Nullable Object
return new NodeSetLazyManipulator<>(
sequence,
decomposedContainerValueFactory,
containerPropertyGenerators,
LazyArbitrary.lazy(() -> ((Arbitrary<?>)value).sample())
);
} else if (value instanceof DefaultArbitraryBuilder) {
return new NodeSetLazyManipulator<>(
sequence,
decomposedContainerValueFactory,
containerPropertyGenerators,
LazyArbitrary.lazy(() -> ((DefaultArbitraryBuilder<?>)value).sample())
);
} else if (value instanceof Supplier) {
return new NodeSetLazyManipulator<>(
sequence,
decomposedContainerValueFactory,
containerPropertyGenerators,
LazyArbitrary.lazy((Supplier<?>)value)
);
} else if (value instanceof LazyArbitrary) {
return new NodeSetLazyManipulator<>(
sequence,
decomposedContainerValueFactory,
containerPropertyGenerators,
(LazyArbitrary<?>)value
);
} else if (value instanceof Unique) {
Expand All @@ -287,6 +296,7 @@ private NodeManipulator convertToNodeManipulator(int sequence, @Nullable Object
return new NodeSetDecomposedValueManipulator<>(
sequence,
decomposedContainerValueFactory,
containerPropertyGenerators,
value
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import static com.navercorp.fixturemonkey.api.type.Types.isAssignable;
import static com.navercorp.fixturemonkey.api.type.Types.nullSafe;

import java.util.Collections;
import java.util.List;
import java.util.function.Function;

Expand All @@ -36,29 +35,37 @@
import com.navercorp.fixturemonkey.api.container.DecomposableJavaContainer;
import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory;
import com.navercorp.fixturemonkey.api.generator.ArbitraryContainerInfo;
import com.navercorp.fixturemonkey.api.generator.ContainerProperty;
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGenerator;
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGeneratorContext;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.property.DefaultTypeDefinition;
import com.navercorp.fixturemonkey.api.property.LazyPropertyGenerator;
import com.navercorp.fixturemonkey.api.property.MapEntryElementProperty;
import com.navercorp.fixturemonkey.api.property.Property;
import com.navercorp.fixturemonkey.api.property.TypeDefinition;
import com.navercorp.fixturemonkey.api.tree.TreeNodeManipulator;
import com.navercorp.fixturemonkey.api.type.Types;
import com.navercorp.fixturemonkey.tree.GenerateFixtureContext;
import com.navercorp.fixturemonkey.tree.ObjectNode;
import com.navercorp.fixturemonkey.tree.StartNodePredicate;

@API(since = "0.4.0", status = Status.MAINTAINED)
public final class NodeSetDecomposedValueManipulator<T> implements NodeManipulator {
private final int sequence;
private final DecomposedContainerValueFactory decomposedContainerValueFactory;
private final List<MatcherOperator<ContainerPropertyGenerator>> containerPropertyGenerators;
@Nullable
private final T value;

public NodeSetDecomposedValueManipulator(
int sequence,
DecomposedContainerValueFactory decomposedContainerValueFactory,
List<MatcherOperator<ContainerPropertyGenerator>> containerPropertyGenerators,
@Nullable T value
) {
this.sequence = sequence;
this.decomposedContainerValueFactory = decomposedContainerValueFactory;
this.containerPropertyGenerators = containerPropertyGenerators;
this.value = value;
}

Expand Down Expand Up @@ -118,17 +125,34 @@ private void setValue(ObjectNode objectNode, @Nullable Object value) {
if (forced) {
ArbitraryContainerInfo containerInfo =
new ArbitraryContainerInfo(decomposedContainerSize, decomposedContainerSize);
objectNode.addTreeNodeManipulator(
new ContainerInfoManipulator(
Collections.singletonList(StartNodePredicate.INSTANCE),

ContainerPropertyGenerator containerPropertyGenerator = containerPropertyGenerators.stream()
.filter(it -> it.match(objectNode.getOriginalProperty()))
.map(MatcherOperator::getOperator)
.findFirst()
.orElseThrow(
() -> new IllegalStateException(
"ContainerPropertyGenerator not found given property" + objectNode.getOriginalProperty()
)
);

ContainerProperty containerProperty = containerPropertyGenerator.generate(
new ContainerPropertyGeneratorContext(
objectNode.getOriginalProperty(),
containerInfo,
sequence
null
)
);
objectNode.forceExpand();
}

objectNode.expand();
objectNode.forceExpand(
new DefaultTypeDefinition(
objectNode.getOriginalProperty(),
new LazyPropertyGenerator(p -> containerProperty.getElementProperties())
)
);
} else {
objectNode.expand();
}
List<ObjectNode> children = nullSafe(objectNode.getChildren()).asList();

if (objectNode.getArbitraryProperty()
Expand Down Expand Up @@ -157,6 +181,7 @@ private void setValue(ObjectNode objectNode, @Nullable Object value) {
return;
}

objectNode.forceExpand();
List<? extends TypeDefinition> typeDefinitions = objectNode.getTreeProperty().getTypeDefinitions();
for (TypeDefinition typeDefinition : typeDefinitions) {
Class<?> actualConcreteType = Types.getActualType(typeDefinition.getResolvedProperty().getType());
Expand All @@ -171,7 +196,6 @@ private void setValue(ObjectNode objectNode, @Nullable Object value) {
objectNode.setResolvedTypeDefinition(typeDefinition);
}

objectNode.forceExpand();
for (ObjectNode child : nullSafe(objectNode.getChildren()).asList()) {
if (!typeDefinition.getResolvedProperty().equals(child.getResolvedParentProperty())) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@

package com.navercorp.fixturemonkey.customizer;

import java.util.List;

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

import net.jqwik.api.Arbitrary;

import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary;
import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory;
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGenerator;
import com.navercorp.fixturemonkey.api.lazy.LazyArbitrary;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.customizer.Values.Just;
import com.navercorp.fixturemonkey.tree.GenerateFixtureContext;
import com.navercorp.fixturemonkey.tree.ObjectNode;
Expand All @@ -34,15 +38,18 @@
public final class NodeSetLazyManipulator<T> implements NodeManipulator {
private final int sequence;
private final DecomposedContainerValueFactory decomposedContainerValueFactory;
private final List<MatcherOperator<ContainerPropertyGenerator>> containerPropertyGenerators;
private final LazyArbitrary<T> lazyArbitrary;

public NodeSetLazyManipulator(
int sequence,
DecomposedContainerValueFactory decomposedContainerValueFactory,
List<MatcherOperator<ContainerPropertyGenerator>> containerPropertyGenerators,
LazyArbitrary<T> lazyArbitrary
) {
this.sequence = sequence;
this.decomposedContainerValueFactory = decomposedContainerValueFactory;
this.containerPropertyGenerators = containerPropertyGenerators;
this.lazyArbitrary = lazyArbitrary;
}

Expand Down Expand Up @@ -70,7 +77,12 @@ public void manipulate(ObjectNode objectNode) {
}

NodeSetDecomposedValueManipulator<T> nodeSetDecomposedValueManipulator =
new NodeSetDecomposedValueManipulator<>(sequence, decomposedContainerValueFactory, value);
new NodeSetDecomposedValueManipulator<>(
sequence,
decomposedContainerValueFactory,
containerPropertyGenerators,
value
);
nodeSetDecomposedValueManipulator.manipulate(objectNode);
lazyArbitrary.clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,10 @@ public ArbitraryGeneratorContext generateContext(
Property resolvedParentProperty = objectNode.getMetadata().getResolvedTypeDefinition().getResolvedProperty();
objectNode.expand();
List<ObjectNode> children = nullSafe(objectNode.getChildren()).asList().stream()
.filter(it -> resolvedParentProperty.equals(it.getMetadata().getResolvedParentProperty()))
.filter(it -> Types.isAssignable(
Types.getActualType(resolvedParentProperty.getType()),
Types.getActualType(it.getMetadata().getResolvedParentProperty().getType()))
)
.collect(Collectors.toList());

for (ObjectNode childNode : children) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ public void forceExpand() {
);
}

@Override
public void forceExpand(TypeDefinition typeDefinition) {
this.traverseNode.forceExpand(typeDefinition);
this.setChildren(
nullSafe(this.traverseNode.getChildren()).asList().stream()
.map(it -> new ObjectNode(it, generateFixtureContext.newChildNodeContext()))
.collect(Collectors.toList())
);
}

@Override
public TraverseNodeMetadata getMetadata() {
return traverseNode.getMetadata();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1609,4 +1609,30 @@ void allArbitraryGeneratorSkipReturnsNull() {

then(actual).isNull();
}

@Property
void setConcrete() {
// given
List<Class<? extends AbstractValue>> implementations = new ArrayList<>();
implementations.add(ConcreteStringValue.class);
implementations.add(ConcreteIntValue.class);

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

ConcreteStringValue expected = new ConcreteStringValue();
expected.setValue("stringValue");
expected.setStringValue("test");

// when
AbstractValue actual = sut.giveMeBuilder(AbstractValue.class)
.set(expected)
.sample();

then(actual).isEqualTo(expected);
}
}

0 comments on commit be0258a

Please sign in to comment.