
com.navercorp.fixturemonkey.FixtureMonkeyBuilder Maven / Gradle / Ivy
/*
* Fixture Monkey
*
* Copyright (c) 2021-present NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.navercorp.fixturemonkey;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
import com.navercorp.fixturemonkey.api.constraint.JavaConstraintGenerator;
import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory;
import com.navercorp.fixturemonkey.api.context.MonkeyContext;
import com.navercorp.fixturemonkey.api.context.MonkeyContextBuilder;
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;
import com.navercorp.fixturemonkey.api.introspector.MatchArbitraryIntrospector;
import com.navercorp.fixturemonkey.api.introspector.NullArbitraryIntrospector;
import com.navercorp.fixturemonkey.api.matcher.AssignableTypeMatcher;
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.FixtureMonkeyOptions;
import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptionsBuilder;
import com.navercorp.fixturemonkey.api.plugin.InterfacePlugin;
import com.navercorp.fixturemonkey.api.plugin.Plugin;
import com.navercorp.fixturemonkey.api.property.CandidateConcretePropertyResolver;
import com.navercorp.fixturemonkey.api.property.PropertyGenerator;
import com.navercorp.fixturemonkey.api.property.PropertyNameResolver;
import com.navercorp.fixturemonkey.api.random.Randoms;
import com.navercorp.fixturemonkey.api.type.Types;
import com.navercorp.fixturemonkey.api.validator.ArbitraryValidator;
import com.navercorp.fixturemonkey.buildergroup.ArbitraryBuilderCandidate;
import com.navercorp.fixturemonkey.buildergroup.ArbitraryBuilderGroup;
import com.navercorp.fixturemonkey.customizer.MonkeyManipulatorFactory;
import com.navercorp.fixturemonkey.expression.ArbitraryExpressionFactory;
import com.navercorp.fixturemonkey.expression.MonkeyExpressionFactory;
import com.navercorp.fixturemonkey.resolver.ManipulatorOptimizer;
import com.navercorp.fixturemonkey.resolver.NoneManipulatorOptimizer;
import com.navercorp.fixturemonkey.tree.ApplyStrictModeResolver;
import com.navercorp.fixturemonkey.tree.ArbitraryTraverser;
@SuppressWarnings("unused")
@API(since = "0.4.0", status = Status.MAINTAINED)
public final class FixtureMonkeyBuilder {
private final FixtureMonkeyOptionsBuilder fixtureMonkeyOptionsBuilder = FixtureMonkeyOptions.builder();
private final List>>>
registeredArbitraryBuilders = new ArrayList<>();
private ManipulatorOptimizer manipulatorOptimizer = new NoneManipulatorOptimizer();
private MonkeyExpressionFactory monkeyExpressionFactory = new ArbitraryExpressionFactory();
private final MonkeyContextBuilder monkeyContextBuilder = MonkeyContext.builder();
private long seed = System.nanoTime();
// The default plugins are listed below.
private InterfacePlugin defaultInterfacePlugin = new InterfacePlugin();
public FixtureMonkeyBuilder pushPropertyGenerator(MatcherOperator propertyGenerator) {
fixtureMonkeyOptionsBuilder.insertFirstPropertyGenerator(propertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushAssignableTypePropertyGenerator(
Class> type,
PropertyGenerator propertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstPropertyGenerator(type, propertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushExactTypePropertyGenerator(Class> type, PropertyGenerator propertyGenerator) {
fixtureMonkeyOptionsBuilder.insertFirstPropertyGenerator(
MatcherOperator.assignableTypeMatchOperator(type, propertyGenerator)
);
return this;
}
public FixtureMonkeyBuilder manipulatorOptimizer(ManipulatorOptimizer manipulatorOptimizer) {
this.manipulatorOptimizer = manipulatorOptimizer;
return this;
}
public FixtureMonkeyBuilder defaultObjectPropertyGenerator(
ObjectPropertyGenerator objectPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.defaultObjectPropertyGenerator(objectPropertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushAssignableTypeObjectPropertyGenerator(
Class> type,
ObjectPropertyGenerator objectPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryObjectPropertyGenerator(type, objectPropertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushExactTypeObjectPropertyGenerator(
Class> type,
ObjectPropertyGenerator objectPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryObjectPropertyGenerator(
MatcherOperator.exactTypeMatchOperator(type, objectPropertyGenerator)
);
return this;
}
public FixtureMonkeyBuilder pushObjectPropertyGenerator(
MatcherOperator objectPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryObjectPropertyGenerator(objectPropertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushAssignableTypeContainerPropertyGenerator(
Class> type,
ContainerPropertyGenerator containerPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryContainerPropertyGenerator(type, containerPropertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushExactTypeContainerPropertyGenerator(
Class> type,
ContainerPropertyGenerator containerPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryContainerPropertyGenerator(
MatcherOperator.exactTypeMatchOperator(type, containerPropertyGenerator)
);
return this;
}
public FixtureMonkeyBuilder pushContainerPropertyGenerator(
MatcherOperator containerPropertyGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryContainerPropertyGenerator(containerPropertyGenerator);
return this;
}
public FixtureMonkeyBuilder pushAssignableTypePropertyNameResolver(
Class> type,
PropertyNameResolver propertyNameResolver
) {
fixtureMonkeyOptionsBuilder.insertFirstPropertyNameResolver(type, propertyNameResolver);
return this;
}
public FixtureMonkeyBuilder pushExactTypePropertyNameResolver(
Class> type,
PropertyNameResolver propertyNameResolver
) {
fixtureMonkeyOptionsBuilder.insertFirstPropertyNameResolver(
MatcherOperator.exactTypeMatchOperator(type, propertyNameResolver)
);
return this;
}
public FixtureMonkeyBuilder pushPropertyNameResolver(
MatcherOperator propertyNameResolver
) {
fixtureMonkeyOptionsBuilder.insertFirstPropertyNameResolver(propertyNameResolver);
return this;
}
public FixtureMonkeyBuilder defaultPropertyNameResolver(PropertyNameResolver propertyNameResolver) {
fixtureMonkeyOptionsBuilder.defaultPropertyNameResolver(propertyNameResolver);
return this;
}
public FixtureMonkeyBuilder pushExactTypeNullInjectGenerator(
Class> type,
NullInjectGenerator nullInjectGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstNullInjectGenerators(
MatcherOperator.exactTypeMatchOperator(type, nullInjectGenerator)
);
return this;
}
public FixtureMonkeyBuilder pushAssignableTypeNullInjectGenerator(
Class> type,
NullInjectGenerator nullInjectGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstNullInjectGenerators(type, nullInjectGenerator);
return this;
}
public FixtureMonkeyBuilder pushNullInjectGenerator(MatcherOperator nullInjectGenerator) {
fixtureMonkeyOptionsBuilder.insertFirstNullInjectGenerators(nullInjectGenerator);
return this;
}
public FixtureMonkeyBuilder defaultNullInjectGenerator(NullInjectGenerator nullInjectGenerator) {
fixtureMonkeyOptionsBuilder.defaultNullInjectGenerator(nullInjectGenerator);
return this;
}
public FixtureMonkeyBuilder pushArbitraryContainerInfoGenerator(
MatcherOperator arbitraryContainerInfoGenerator
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryContainerInfoGenerator(arbitraryContainerInfoGenerator);
return this;
}
public FixtureMonkeyBuilder defaultArbitraryContainerInfoGenerator(
ArbitraryContainerInfoGenerator defaultArbitraryContainerInfoGenerator) {
fixtureMonkeyOptionsBuilder.defaultArbitraryContainerInfoGenerator(defaultArbitraryContainerInfoGenerator);
return this;
}
public FixtureMonkeyBuilder pushAssignableTypeArbitraryIntrospector(
Class> type,
ArbitraryIntrospector arbitraryIntrospector
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryIntrospector(type, arbitraryIntrospector);
return this;
}
public FixtureMonkeyBuilder pushExactTypeArbitraryIntrospector(
Class> type,
ArbitraryIntrospector arbitraryIntrospector
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryIntrospector(
MatcherOperator.exactTypeMatchOperator(type, arbitraryIntrospector)
);
return this;
}
public FixtureMonkeyBuilder pushArbitraryIntrospector(
MatcherOperator arbitraryIntrospector
) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryIntrospector(arbitraryIntrospector);
return this;
}
public FixtureMonkeyBuilder objectIntrospector(ArbitraryIntrospector objectIntrospector) {
this.fixtureMonkeyOptionsBuilder.objectIntrospector(it -> objectIntrospector);
return this;
}
public FixtureMonkeyBuilder arbitraryValidator(ArbitraryValidator arbitraryValidator) {
this.fixtureMonkeyOptionsBuilder.defaultArbitraryValidator(arbitraryValidator);
return this;
}
public FixtureMonkeyBuilder pushExceptGenerateType(Matcher matcher) {
fixtureMonkeyOptionsBuilder.insertFirstArbitraryIntrospector(
new MatcherOperator<>(
matcher,
NullArbitraryIntrospector.INSTANCE
)
);
return this;
}
public FixtureMonkeyBuilder addExceptGenerateClass(Class> type) {
return pushExceptGenerateType(new AssignableTypeMatcher(type));
}
public FixtureMonkeyBuilder addExceptGenerateClasses(Class>... types) {
for (Class> type : types) {
addExceptGenerateClass(type);
}
return this;
}
public FixtureMonkeyBuilder addExceptGeneratePackage(String exceptGeneratePackage) {
return pushExceptGenerateType(
property -> Types.primitiveToWrapper(Types.getActualType(property.getType()))
.getPackage()
.getName()
.startsWith(exceptGeneratePackage)
);
}
public FixtureMonkeyBuilder addExceptGeneratePackages(String... exceptGeneratePackages) {
for (String exceptGeneratePackage : exceptGeneratePackages) {
addExceptGeneratePackage(exceptGeneratePackage);
}
return this;
}
public FixtureMonkeyBuilder register(
Class> type,
Function> registeredArbitraryBuilder
) {
return this.register(MatcherOperator.assignableTypeMatchOperator(type, registeredArbitraryBuilder));
}
public FixtureMonkeyBuilder registerExactType(
Class> type,
Function> registeredArbitraryBuilder
) {
return this.register(MatcherOperator.exactTypeMatchOperator(type, registeredArbitraryBuilder));
}
public FixtureMonkeyBuilder registerAssignableType(
Class> type,
Function> registeredArbitraryBuilder
) {
return this.register(MatcherOperator.assignableTypeMatchOperator(type, registeredArbitraryBuilder));
}
public FixtureMonkeyBuilder register(
MatcherOperator>> registeredArbitraryBuilder
) {
this.registeredArbitraryBuilders.add(registeredArbitraryBuilder);
return this;
}
public FixtureMonkeyBuilder registerGroup(Class>... arbitraryBuilderGroups) {
for (Class> arbitraryBuilderGroup : arbitraryBuilderGroups) {
Method[] methods = arbitraryBuilderGroup.getMethods();
for (Method method : methods) {
int paramCount = method.getParameterCount();
Class> returnType = method.getReturnType();
if (paramCount != 1 || !ArbitraryBuilder.class.isAssignableFrom(returnType)) {
continue;
}
try {
Class> actualType = Types.getActualType(
Types.getGenericsTypes(method.getAnnotatedReturnType()).get(0)
);
Object noArgsInstance = arbitraryBuilderGroup.getDeclaredConstructor().newInstance();
Function> registerArbitraryBuilder =
(fixtureMonkey) -> {
try {
return (ArbitraryBuilder>)method.invoke(noArgsInstance, fixtureMonkey);
} catch (IllegalAccessException | InvocationTargetException ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
};
this.register(actualType, registerArbitraryBuilder);
} catch (Exception ex) {
// ignored
}
}
}
return this;
}
public FixtureMonkeyBuilder registerGroup(ArbitraryBuilderGroup... arbitraryBuilderGroups) {
for (ArbitraryBuilderGroup arbitraryBuilderGroup : arbitraryBuilderGroups) {
List> candidates = arbitraryBuilderGroup.generateCandidateList()
.getCandidates();
for (ArbitraryBuilderCandidate> candidate : candidates) {
this.register(
candidate.getClassType(),
candidate.getArbitraryBuilderRegisterer()
);
}
}
return this;
}
public FixtureMonkeyBuilder plugin(Plugin plugin) {
if (plugin instanceof InterfacePlugin) { // TODO: Added for backward compatibility. It will be removed in 1.1.0
this.defaultInterfacePlugin = (InterfacePlugin)plugin;
return this;
}
fixtureMonkeyOptionsBuilder.plugin(plugin);
return this;
}
public FixtureMonkeyBuilder defaultDecomposedContainerValueFactory(
DecomposedContainerValueFactory defaultDecomposedContainerValueFactory
) {
fixtureMonkeyOptionsBuilder.decomposedContainerValueFactory(defaultDecomposedContainerValueFactory);
return this;
}
public FixtureMonkeyBuilder addDecomposedContainerValueFactory(
Class> type,
DecomposedContainerValueFactory additionalDecomposedContainerValueFactory
) {
fixtureMonkeyOptionsBuilder.addDecomposedContainerValueFactory(type, additionalDecomposedContainerValueFactory);
return this;
}
public FixtureMonkeyBuilder pushContainerIntrospector(ArbitraryIntrospector containerIntrospector) {
this.fixtureMonkeyOptionsBuilder.containerIntrospector(it ->
new MatchArbitraryIntrospector(
Arrays.asList(
containerIntrospector,
it
)
)
);
return this;
}
public FixtureMonkeyBuilder addContainerType(
Class> type,
ContainerPropertyGenerator containerObjectPropertyGenerator,
ArbitraryIntrospector containerArbitraryIntrospector,
DecomposedContainerValueFactory decomposedContainerValueFactory
) {
this.pushAssignableTypeContainerPropertyGenerator(type, containerObjectPropertyGenerator);
this.pushContainerIntrospector(containerArbitraryIntrospector);
this.fixtureMonkeyOptionsBuilder.addDecomposedContainerValueFactory(type, decomposedContainerValueFactory);
return this;
}
public FixtureMonkeyBuilder defaultPropertyGenerator(PropertyGenerator propertyGenerator) {
this.fixtureMonkeyOptionsBuilder.defaultPropertyGenerator(propertyGenerator);
return this;
}
public FixtureMonkeyBuilder defaultNotNull(boolean defaultNotNull) {
this.fixtureMonkeyOptionsBuilder.defaultNotNull(defaultNotNull);
return this;
}
public FixtureMonkeyBuilder nullableContainer(boolean nullableContainer) {
this.fixtureMonkeyOptionsBuilder.nullableContainer(nullableContainer);
return this;
}
public FixtureMonkeyBuilder nullableElement(boolean nullableElement) {
this.fixtureMonkeyOptionsBuilder.nullableElement(nullableElement);
return this;
}
/**
* It is deprecated. Please use {@link InterfacePlugin#interfaceImplements(Matcher, List)} instead.
*/
@Deprecated
public FixtureMonkeyBuilder interfaceImplements(
Matcher matcher,
List> implementations
) {
this.pushObjectPropertyGenerator(
new MatcherOperator<>(matcher, new InterfaceObjectPropertyGenerator<>(implementations))
);
return this;
}
/**
* It is deprecated. Please use {@link InterfacePlugin#interfaceImplements(Class, List)} instead.
*/
@Deprecated
public FixtureMonkeyBuilder interfaceImplements(
Class interfaceClass,
List> implementations
) {
return this.interfaceImplements(new ExactTypeMatcher(interfaceClass), implementations);
}
public FixtureMonkeyBuilder useExpressionStrictMode() {
this.monkeyExpressionFactory = expression ->
() -> new ApplyStrictModeResolver(new ArbitraryExpressionFactory().from(expression).toNodeResolver());
return this;
}
public FixtureMonkeyBuilder defaultArbitraryGenerator(
UnaryOperator arbitraryGeneratorUnaryOperator
) {
this.fixtureMonkeyOptionsBuilder.defaultArbitraryGenerator(arbitraryGeneratorUnaryOperator);
return this;
}
public FixtureMonkeyBuilder generateMaxTries(int generateMaxTries) {
fixtureMonkeyOptionsBuilder.generateMaxTries(generateMaxTries);
return this;
}
public FixtureMonkeyBuilder generateUniqueMaxTries(int generateUniqueMaxTries) {
fixtureMonkeyOptionsBuilder.generateUniqueMaxTries(generateUniqueMaxTries);
return this;
}
public FixtureMonkeyBuilder javaConstraintGenerator(JavaConstraintGenerator javaConstraintGenerator) {
fixtureMonkeyOptionsBuilder.javaConstraintGenerator(javaConstraintGenerator);
return this;
}
public FixtureMonkeyBuilder pushJavaConstraintGeneratorCustomizer(
UnaryOperator javaConstraintGeneratorCustomizer
) {
fixtureMonkeyOptionsBuilder.insertFirstJavaConstraintGeneratorCustomizer(javaConstraintGeneratorCustomizer);
return this;
}
/**
* It is deprecated. Please use {@code @Seed} in fixture-monkey-junit-jupiter module.
*/
@Deprecated
public FixtureMonkeyBuilder seed(long seed) {
this.seed = seed;
return this;
}
/**
* Use {@link InterfacePlugin#interfaceImplements(Class, List)}
* or {@link InterfacePlugin#abstractClassExtends(Class, List)} instead.
*/
@Deprecated
public FixtureMonkeyBuilder pushExactTypePropertyCandidateResolver(
Class> type,
CandidateConcretePropertyResolver candidateConcretePropertyResolver
) {
fixtureMonkeyOptionsBuilder.insertFirstCandidateConcretePropertyResolvers(
new MatcherOperator<>(
new ExactTypeMatcher(type),
candidateConcretePropertyResolver
)
);
return this;
}
public FixtureMonkey build() {
defaultInterfacePlugin.accept(fixtureMonkeyOptionsBuilder);
FixtureMonkeyOptions fixtureMonkeyOptions = fixtureMonkeyOptionsBuilder.build();
ArbitraryTraverser traverser = new ArbitraryTraverser(fixtureMonkeyOptions);
MonkeyManipulatorFactory monkeyManipulatorFactory = new MonkeyManipulatorFactory(
new AtomicInteger(),
monkeyExpressionFactory,
traverser,
fixtureMonkeyOptions.getDecomposedContainerValueFactory()
);
MonkeyContext monkeyContext = monkeyContextBuilder.build();
Randoms.create(String.valueOf(seed));
return new FixtureMonkey(
fixtureMonkeyOptions,
traverser,
manipulatorOptimizer,
monkeyContext,
registeredArbitraryBuilders,
monkeyManipulatorFactory
);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy