Skip to content

Commit

Permalink
Add priority feature
Browse files Browse the repository at this point in the history
Signed-off-by: yongjunhong <[email protected]>
  • Loading branch information
YongGoose committed Dec 6, 2024
1 parent b2abc78 commit 6e64284
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

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

import org.apiguardian.api.API;
Expand All @@ -42,6 +44,7 @@
import com.navercorp.fixturemonkey.api.type.TypeReference;
import com.navercorp.fixturemonkey.customizer.ArbitraryManipulator;
import com.navercorp.fixturemonkey.customizer.MonkeyManipulatorFactory;
import com.navercorp.fixturemonkey.customizer.PriorityMatcherOperator;
import com.navercorp.fixturemonkey.experimental.ExperimentalArbitraryBuilder;
import com.navercorp.fixturemonkey.resolver.ArbitraryBuilderContext;
import com.navercorp.fixturemonkey.resolver.ArbitraryResolver;
Expand All @@ -57,24 +60,26 @@ public final class FixtureMonkey {
private final MonkeyContext monkeyContext;
private final List<MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuilders = new ArrayList<>();
private final MonkeyManipulatorFactory monkeyManipulatorFactory;
private final Map<Integer, List<MatcherOperator<? extends ArbitraryBuilder<?>>>>
priorityGroupedMatchers = new HashMap<>();

public FixtureMonkey(
FixtureMonkeyOptions fixtureMonkeyOptions,
ArbitraryTraverser traverser,
ManipulatorOptimizer manipulatorOptimizer,
MonkeyContext monkeyContext,
List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> registeredArbitraryBuilders,
List<PriorityMatcherOperator> registeredArbitraryBuilders,
MonkeyManipulatorFactory monkeyManipulatorFactory,
Map<String, MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> mapsByRegisteredName
Map<String, PriorityMatcherOperator> mapsByRegisteredName
) {
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
this.traverser = traverser;
this.manipulatorOptimizer = manipulatorOptimizer;
this.monkeyContext = monkeyContext;
this.monkeyManipulatorFactory = monkeyManipulatorFactory;
initializeRegisteredArbitraryBuilders(registeredArbitraryBuilders);
initializeNamedArbitraryBuilderMap(mapsByRegisteredName);
shuffleRegisteredArbitraryBuilders();
groupMatchersByPriorityFromList(registeredArbitraryBuilders);
groupMatchersByPriorityFromNamedMap(mapsByRegisteredName);
shuffleAndRegisterByPriority(priorityGroupedMatchers);
}

public static FixtureMonkeyBuilder builder() {
Expand Down Expand Up @@ -191,33 +196,51 @@ public <T> Arbitrary<T> giveMeArbitrary(TypeReference<T> typeReference) {
return this.giveMeBuilder(typeReference).build();
}

private void initializeRegisteredArbitraryBuilders(
List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> registeredArbitraryBuilders
private void groupMatchersByPriorityFromList(
List<PriorityMatcherOperator> registeredArbitraryBuilders
) {
List<? extends MatcherOperator<? extends ArbitraryBuilder<?>>> generatedRegisteredArbitraryBuilder =
registeredArbitraryBuilders.stream()
.map(it -> new MatcherOperator<>(it.getMatcher(), it.getOperator().apply(this)))
.collect(toList());

for (int i = generatedRegisteredArbitraryBuilder.size() - 1; i >= 0; i--) {
this.registeredArbitraryBuilders.add(generatedRegisteredArbitraryBuilder.get(i));
}
priorityGroupedMatchers.putAll(
registeredArbitraryBuilders
.stream()
.collect(Collectors.groupingBy(
PriorityMatcherOperator::getPriority,
Collectors.mapping(
it -> new MatcherOperator<>(
it.getMatcherOperator(), it.getMatcherOperator().getOperator().apply(this)
),
Collectors.toList()
)
))
);
}

private void initializeNamedArbitraryBuilderMap(
Map<String, MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> mapsByRegisteredName
private void groupMatchersByPriorityFromNamedMap(
Map<String, PriorityMatcherOperator> mapsByRegisteredName
) {
mapsByRegisteredName.forEach((registeredName, matcherOperator) -> {
registeredArbitraryBuilders.add(
new MatcherOperator<>(
new NamedMatcher(matcherOperator.getMatcher(), registeredName),
matcherOperator.getOperator().apply(this)
)
);
});
priorityGroupedMatchers.putAll(
mapsByRegisteredName.entrySet().stream()
.collect(Collectors.groupingBy(
entry -> entry.getValue().getPriority(),
Collectors.mapping(
entry -> new MatcherOperator<>(
new NamedMatcher(entry.getValue().getMatcherOperator().getMatcher(), entry.getKey()),
entry.getValue().getMatcherOperator().getOperator().apply(this)
),
Collectors.toList()
)
))
);
}

private void shuffleRegisteredArbitraryBuilders() {
Collections.shuffle(registeredArbitraryBuilders, Randoms.current());
private void shuffleAndRegisterByPriority(
Map<Integer, List<MatcherOperator<? extends ArbitraryBuilder<?>>>> groupedByPriority
) {
TreeMap<Integer, List<MatcherOperator<? extends ArbitraryBuilder<?>>>> sortedGroupedByPriority =
new TreeMap<>(groupedByPriority);

sortedGroupedByPriority.forEach((priority, matcherOperators) -> {
Collections.shuffle(matcherOperators, Randoms.current());
this.registeredArbitraryBuilders.addAll(matcherOperators);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;

import com.navercorp.fixturemonkey.annotation.Order;
import com.navercorp.fixturemonkey.api.constraint.JavaConstraintGenerator;
import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory;
import com.navercorp.fixturemonkey.api.context.MonkeyContext;
Expand Down Expand Up @@ -62,6 +63,7 @@
import com.navercorp.fixturemonkey.buildergroup.ArbitraryBuilderCandidate;
import com.navercorp.fixturemonkey.buildergroup.ArbitraryBuilderGroup;
import com.navercorp.fixturemonkey.customizer.MonkeyManipulatorFactory;
import com.navercorp.fixturemonkey.customizer.PriorityMatcherOperator;
import com.navercorp.fixturemonkey.expression.ArbitraryExpressionFactory;
import com.navercorp.fixturemonkey.expression.MonkeyExpressionFactory;
import com.navercorp.fixturemonkey.resolver.ManipulatorOptimizer;
Expand All @@ -73,13 +75,11 @@
@API(since = "0.4.0", status = Status.MAINTAINED)
public final class FixtureMonkeyBuilder {
private final FixtureMonkeyOptionsBuilder fixtureMonkeyOptionsBuilder = FixtureMonkeyOptions.builder();
private final List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>>
registeredArbitraryBuilders = new ArrayList<>();
private final List<PriorityMatcherOperator> registeredArbitraryBuilders = new ArrayList<>();
private ManipulatorOptimizer manipulatorOptimizer = new NoneManipulatorOptimizer();
private MonkeyExpressionFactory monkeyExpressionFactory = new ArbitraryExpressionFactory();
private final MonkeyContextBuilder monkeyContextBuilder = MonkeyContext.builder();
private final Map<String, MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>>
registeredArbitraryListByRegisteredName = new HashMap<>();
private final Map<String, PriorityMatcherOperator> registeredArbitraryListByRegisteredName = new HashMap<>();
private long seed = System.nanoTime();

// The default plugins are listed below.
Expand Down Expand Up @@ -317,6 +317,14 @@ public FixtureMonkeyBuilder register(
return this.register(MatcherOperator.assignableTypeMatchOperator(type, registeredArbitraryBuilder));
}

public FixtureMonkeyBuilder register(
Class<?> type,
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> registeredArbitraryBuilder,
int priority
) {
return this.register(MatcherOperator.assignableTypeMatchOperator(type, registeredArbitraryBuilder), priority);
}

public FixtureMonkeyBuilder registerExactType(
Class<?> type,
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> registeredArbitraryBuilder
Expand All @@ -334,7 +342,15 @@ public FixtureMonkeyBuilder registerAssignableType(
public FixtureMonkeyBuilder register(
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> registeredArbitraryBuilder
) {
this.registeredArbitraryBuilders.add(registeredArbitraryBuilder);
this.registeredArbitraryBuilders.add(new PriorityMatcherOperator(registeredArbitraryBuilder));
return this;
}

public FixtureMonkeyBuilder register(
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> registeredArbitraryBuilder,
int priority
) {
this.registeredArbitraryBuilders.add(new PriorityMatcherOperator(registeredArbitraryBuilder, priority));
return this;
}

Expand All @@ -361,6 +377,11 @@ public FixtureMonkeyBuilder registerGroup(Class<?>... arbitraryBuilderGroups) {
throw new RuntimeException(ex);
}
};

if (arbitraryBuilderGroup.isAnnotationPresent(Order.class)) {
Order order = arbitraryBuilderGroup.getAnnotation(Order.class);
this.register(actualType, registerArbitraryBuilder, order.value());
}
this.register(actualType, registerArbitraryBuilder);
} catch (Exception ex) {
// ignored
Expand All @@ -385,6 +406,23 @@ public FixtureMonkeyBuilder registerGroup(ArbitraryBuilderGroup... arbitraryBuil
return this;
}

public FixtureMonkeyBuilder registerGroup(
ArbitraryBuilderGroup arbitraryBuilderGroup,
int priority
) {
List<ArbitraryBuilderCandidate<?>> candidates = arbitraryBuilderGroup.generateCandidateList()
.getCandidates();

for (ArbitraryBuilderCandidate<?> candidate : candidates) {
this.register(
candidate.getClassType(),
candidate.getArbitraryBuilderRegisterer(),
priority
);
}
return this;
}

public FixtureMonkeyBuilder registeredName(
String registeredName,
Class<?> type,
Expand All @@ -396,7 +434,25 @@ public FixtureMonkeyBuilder registeredName(
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> matcherOperator =
MatcherOperator.assignableTypeMatchOperator(type, arbitraryBuilder);

this.registeredArbitraryListByRegisteredName.put(registeredName, matcherOperator);
this.registeredArbitraryListByRegisteredName.put(registeredName, new PriorityMatcherOperator(matcherOperator));
return this;
}

public FixtureMonkeyBuilder registeredName(
String registeredName,
Class<?> type,
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> arbitraryBuilder,
int priority
) {
if (registeredArbitraryListByRegisteredName.containsKey(registeredName)) {
throw new IllegalArgumentException("Duplicated ArbitraryBuilder name: " + registeredName);
}
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> matcherOperator =
MatcherOperator.assignableTypeMatchOperator(type, arbitraryBuilder);

this.registeredArbitraryListByRegisteredName.put(
registeredName, new PriorityMatcherOperator(matcherOperator, priority)
);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Order {
int value() default 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.customizer;

import java.util.function.Function;

import com.navercorp.fixturemonkey.ArbitraryBuilder;
import com.navercorp.fixturemonkey.FixtureMonkey;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;

public final class PriorityMatcherOperator {
private final int priority;
private final MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> matcherOperator;

public PriorityMatcherOperator(
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> matcherOperator,
int priority
) {
checkPriority(priority);
this.matcherOperator = matcherOperator;
this.priority = priority;
}

public PriorityMatcherOperator(
final MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> matcherOperator
) {
this.priority = Integer.MAX_VALUE;
this.matcherOperator = matcherOperator;
}

public int getPriority() {
return priority;
}

public MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> getMatcherOperator() {
return matcherOperator;
}

private void checkPriority(int priority) {
if (priority < 0) {
throw new IllegalArgumentException("Priority must be greater than or equal to 0");
}
}
}
Loading

0 comments on commit 6e64284

Please sign in to comment.