-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Random Selection of Register Operations When Not Using selectName #1108
base: 31-register
Are you sure you want to change the base?
Changes from 7 commits
b2abc78
6e64284
6fa32d7
486cf5f
d00d7a7
36c424a
43e59aa
478bb7a
8bacdc2
6f5e9f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ | |
import static java.util.stream.Collectors.toList; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Function; | ||
|
@@ -36,10 +38,12 @@ | |
import com.navercorp.fixturemonkey.api.matcher.NamedMatcher; | ||
import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptions; | ||
import com.navercorp.fixturemonkey.api.property.RootProperty; | ||
import com.navercorp.fixturemonkey.api.random.Randoms; | ||
import com.navercorp.fixturemonkey.api.type.LazyAnnotatedType; | ||
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; | ||
|
@@ -53,25 +57,28 @@ public final class FixtureMonkey { | |
private final ArbitraryTraverser traverser; | ||
private final ManipulatorOptimizer manipulatorOptimizer; | ||
private final MonkeyContext monkeyContext; | ||
private final List<MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuilders = new ArrayList<>(); | ||
private final List<PriorityMatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuilders | ||
= new ArrayList<>(); | ||
private final MonkeyManipulatorFactory monkeyManipulatorFactory; | ||
|
||
public FixtureMonkey( | ||
FixtureMonkeyOptions fixtureMonkeyOptions, | ||
ArbitraryTraverser traverser, | ||
ManipulatorOptimizer manipulatorOptimizer, | ||
MonkeyContext monkeyContext, | ||
List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> registeredArbitraryBuilders, | ||
List<PriorityMatcherOperator<Function<FixtureMonkey, | ||
? extends ArbitraryBuilder<?>>>> registeredArbitraryBuildersWithPriority, | ||
MonkeyManipulatorFactory monkeyManipulatorFactory, | ||
Map<String, MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> mapsByRegisteredName | ||
Map<String, PriorityMatcherOperator<Function<FixtureMonkey, | ||
? extends ArbitraryBuilder<?>>>> registeredPriorityMatchersByName | ||
) { | ||
this.fixtureMonkeyOptions = fixtureMonkeyOptions; | ||
this.traverser = traverser; | ||
this.manipulatorOptimizer = manipulatorOptimizer; | ||
this.monkeyContext = monkeyContext; | ||
this.monkeyManipulatorFactory = monkeyManipulatorFactory; | ||
initializeRegisteredArbitraryBuilders(registeredArbitraryBuilders); | ||
initializeNamedArbitraryBuilderMap(mapsByRegisteredName); | ||
initializeRegisteredArbitraryBuilders(registeredArbitraryBuildersWithPriority); | ||
initializeNamedArbitraryBuilderMap(registeredPriorityMatchersByName); | ||
} | ||
|
||
public static FixtureMonkeyBuilder builder() { | ||
|
@@ -91,8 +98,20 @@ public <T> ArbitraryBuilder<T> giveMeBuilder(Class<T> type) { | |
public <T> ArbitraryBuilder<T> giveMeBuilder(TypeReference<T> type) { | ||
RootProperty rootProperty = new RootProperty(type.getAnnotatedType()); | ||
|
||
ArbitraryBuilderContext builderContext = registeredArbitraryBuilders.stream() | ||
List<PriorityMatcherOperator<? extends ArbitraryBuilder<?>>> priorityOperators = registeredArbitraryBuilders | ||
.stream() | ||
.filter(it -> it.match(rootProperty)) | ||
.sorted(Comparator.comparingInt(PriorityMatcherOperator::getPriority)) | ||
.collect(toList()); | ||
|
||
List<PriorityMatcherOperator<? extends ArbitraryBuilder<?>>> highestPriorityOperators | ||
= getHighestPriorityOperators(priorityOperators); | ||
|
||
if (highestPriorityOperators.size() > 1) { | ||
Collections.shuffle(highestPriorityOperators, Randoms.current()); | ||
} | ||
|
||
ArbitraryBuilderContext builderContext = highestPriorityOperators.stream() | ||
.map(MatcherOperator::getOperator) | ||
.findAny() | ||
.map(DefaultArbitraryBuilder.class::cast) | ||
|
@@ -120,6 +139,20 @@ public <T> ArbitraryBuilder<T> giveMeBuilder(TypeReference<T> type) { | |
); | ||
} | ||
|
||
private List<PriorityMatcherOperator<? extends ArbitraryBuilder<?>>> getHighestPriorityOperators( | ||
List<PriorityMatcherOperator<? extends ArbitraryBuilder<?>>> priorityOperators | ||
) { | ||
if (priorityOperators.isEmpty()) { | ||
return priorityOperators; | ||
} | ||
|
||
int highestPriority = priorityOperators.get(0).getPriority(); | ||
|
||
return priorityOperators.stream() | ||
.filter(it -> it.getPriority() == highestPriority) | ||
.collect(toList()); | ||
} | ||
|
||
public <T> ArbitraryBuilder<T> giveMeBuilder(T value) { | ||
ArbitraryBuilderContext context = new ArbitraryBuilderContext(); | ||
|
||
|
@@ -189,11 +222,14 @@ public <T> Arbitrary<T> giveMeArbitrary(TypeReference<T> typeReference) { | |
} | ||
|
||
private void initializeRegisteredArbitraryBuilders( | ||
List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> registeredArbitraryBuilders | ||
List<PriorityMatcherOperator<Function<FixtureMonkey, | ||
? extends ArbitraryBuilder<?>>>> registeredArbitraryBuildersWithPriority | ||
) { | ||
List<? extends MatcherOperator<? extends ArbitraryBuilder<?>>> generatedRegisteredArbitraryBuilder = | ||
registeredArbitraryBuilders.stream() | ||
.map(it -> new MatcherOperator<>(it.getMatcher(), it.getOperator().apply(this))) | ||
List<? extends PriorityMatcherOperator<? extends ArbitraryBuilder<?>>> generatedRegisteredArbitraryBuilder = | ||
registeredArbitraryBuildersWithPriority.stream() | ||
.map(it -> new PriorityMatcherOperator<>( | ||
it.getMatcher(), it.getOperator().apply(this), it.getPriority()) | ||
) | ||
.collect(toList()); | ||
|
||
for (int i = generatedRegisteredArbitraryBuilder.size() - 1; i >= 0; i--) { | ||
|
@@ -202,13 +238,15 @@ private void initializeRegisteredArbitraryBuilders( | |
} | ||
|
||
private void initializeNamedArbitraryBuilderMap( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이러면 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 commit에서 작업했습니다. b2abc78 검토 부탁드립니다 :) |
||
Map<String, MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> mapsByRegisteredName | ||
Map<String, PriorityMatcherOperator<Function<FixtureMonkey, | ||
? extends ArbitraryBuilder<?>>>> mapsByRegisteredName | ||
) { | ||
mapsByRegisteredName.forEach((registeredName, matcherOperator) -> { | ||
registeredArbitraryBuilders.add( | ||
new MatcherOperator<>( | ||
new PriorityMatcherOperator<>( | ||
new NamedMatcher(matcherOperator.getMatcher(), registeredName), | ||
matcherOperator.getOperator().apply(this) | ||
matcherOperator.getOperator().apply(this), | ||
matcherOperator.getPriority() | ||
) | ||
); | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -72,14 +74,16 @@ | |
@SuppressWarnings("unused") | ||
@API(since = "0.4.0", status = Status.MAINTAINED) | ||
public final class FixtureMonkeyBuilder { | ||
private static final int DEFAULT_PRIORITY = Integer.MAX_VALUE; | ||
|
||
private final FixtureMonkeyOptionsBuilder fixtureMonkeyOptionsBuilder = FixtureMonkeyOptions.builder(); | ||
private final List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> | ||
registeredArbitraryBuilders = new ArrayList<>(); | ||
private final List<PriorityMatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> | ||
registeredArbitraryBuildersWithPriority = 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<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> | ||
registeredPriorityMatchersByName = new HashMap<>(); | ||
private long seed = System.nanoTime(); | ||
|
||
// The default plugins are listed below. | ||
|
@@ -310,11 +314,37 @@ public FixtureMonkeyBuilder addExceptGeneratePackages(String... exceptGeneratePa | |
return this; | ||
} | ||
|
||
/** | ||
* Registers an ArbitraryBuilder with the DEFAULT priority (Integer.MAX_VALUE). | ||
* | ||
* @param registeredArbitraryBuilder the MatcherOperator containing the matcher | ||
* and the ArbitraryBuilder to be registered | ||
* @return the current instance of FixtureMonkeyBuilder for method chaining | ||
*/ | ||
public FixtureMonkeyBuilder register( | ||
Class<?> type, | ||
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> registeredArbitraryBuilder | ||
) { | ||
return this.register(MatcherOperator.assignableTypeMatchOperator(type, registeredArbitraryBuilder)); | ||
return this.register(type, registeredArbitraryBuilder, DEFAULT_PRIORITY); | ||
} | ||
|
||
/** | ||
* Registers an ArbitraryBuilder with a specified priority. | ||
* | ||
* @param registeredArbitraryBuilder the MatcherOperator containing the matcher | ||
* and the ArbitraryBuilder to be registered | ||
* @param priority the priority of the ArbitraryBuilder; higher values indicate lower priority | ||
* @return the current instance of FixtureMonkeyBuilder for method chaining | ||
* @throws IllegalArgumentException if the priority is less than 0 | ||
* | ||
* If multiple ArbitraryBuilders have the same priority, one of them will be selected randomly. | ||
*/ | ||
public FixtureMonkeyBuilder register( | ||
Class<?> type, | ||
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> registeredArbitraryBuilder, | ||
int priority | ||
) { | ||
return this.register(MatcherOperator.assignableTypeMatchOperator(type, registeredArbitraryBuilder), priority); | ||
} | ||
|
||
public FixtureMonkeyBuilder registerExactType( | ||
|
@@ -334,7 +364,18 @@ public FixtureMonkeyBuilder registerAssignableType( | |
public FixtureMonkeyBuilder register( | ||
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> registeredArbitraryBuilder | ||
) { | ||
this.registeredArbitraryBuilders.add(registeredArbitraryBuilder); | ||
return this.register(registeredArbitraryBuilder, DEFAULT_PRIORITY); | ||
} | ||
|
||
public FixtureMonkeyBuilder register( | ||
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> registeredArbitraryBuilder, | ||
int priority | ||
) { | ||
this.registeredArbitraryBuildersWithPriority.add( | ||
new PriorityMatcherOperator<>( | ||
registeredArbitraryBuilder.getMatcher(), registeredArbitraryBuilder.getOperator(), priority | ||
) | ||
); | ||
return this; | ||
} | ||
|
||
|
@@ -361,6 +402,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 | ||
|
@@ -372,15 +418,24 @@ public FixtureMonkeyBuilder registerGroup(Class<?>... arbitraryBuilderGroups) { | |
|
||
public FixtureMonkeyBuilder registerGroup(ArbitraryBuilderGroup... arbitraryBuilderGroups) { | ||
for (ArbitraryBuilderGroup arbitraryBuilderGroup : arbitraryBuilderGroups) { | ||
List<ArbitraryBuilderCandidate<?>> candidates = arbitraryBuilderGroup.generateCandidateList() | ||
.getCandidates(); | ||
|
||
for (ArbitraryBuilderCandidate<?> candidate : candidates) { | ||
this.register( | ||
candidate.getClassType(), | ||
candidate.getArbitraryBuilderRegisterer() | ||
); | ||
} | ||
this.registerGroup(arbitraryBuilderGroup, DEFAULT_PRIORITY); | ||
} | ||
return this; | ||
} | ||
|
||
public FixtureMonkeyBuilder registerGroup( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일단 이 옵션은 제공하지 않는 게 좋을 것 같습니다. 나중에 필요하면 추가하는 방향이 좋아보입니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좋은 것 같습니다. 해당 커밋에서 작업했습니다 8bacdc2 ! |
||
ArbitraryBuilderGroup arbitraryBuilderGroup, | ||
int priority | ||
) { | ||
List<ArbitraryBuilderCandidate<?>> candidates = arbitraryBuilderGroup.generateCandidateList() | ||
.getCandidates(); | ||
|
||
for (ArbitraryBuilderCandidate<?> candidate : candidates) { | ||
this.register( | ||
candidate.getClassType(), | ||
candidate.getArbitraryBuilderRegisterer(), | ||
priority | ||
); | ||
} | ||
return this; | ||
} | ||
|
@@ -390,13 +445,26 @@ public FixtureMonkeyBuilder registeredName( | |
Class<?> type, | ||
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> arbitraryBuilder | ||
) { | ||
if (registeredArbitraryListByRegisteredName.containsKey(registeredName)) { | ||
return this.registeredName(registeredName, type, arbitraryBuilder, DEFAULT_PRIORITY); | ||
} | ||
|
||
public FixtureMonkeyBuilder registeredName( | ||
String registeredName, | ||
Class<?> type, | ||
Function<FixtureMonkey, ? extends ArbitraryBuilder<?>> arbitraryBuilder, | ||
int priority | ||
) { | ||
if (registeredPriorityMatchersByName.containsKey(registeredName)) { | ||
throw new IllegalArgumentException("Duplicated ArbitraryBuilder name: " + registeredName); | ||
} | ||
MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>> matcherOperator = | ||
MatcherOperator.assignableTypeMatchOperator(type, arbitraryBuilder); | ||
|
||
this.registeredArbitraryListByRegisteredName.put(registeredName, matcherOperator); | ||
this.registeredPriorityMatchersByName.put( | ||
registeredName, new PriorityMatcherOperator<>( | ||
matcherOperator.getMatcher(), matcherOperator.getOperator(), priority | ||
) | ||
); | ||
return this; | ||
} | ||
|
||
|
@@ -570,9 +638,9 @@ public FixtureMonkey build() { | |
traverser, | ||
manipulatorOptimizer, | ||
monkeyContext, | ||
registeredArbitraryBuilders, | ||
registeredArbitraryBuildersWithPriority, | ||
monkeyManipulatorFactory, | ||
registeredArbitraryListByRegisteredName | ||
registeredPriorityMatchersByName | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* 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 static org.apiguardian.api.API.Status.EXPERIMENTAL; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
import org.apiguardian.api.API; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ElementType.TYPE}) | ||
@API(since = "1.1.10", status = EXPERIMENTAL) | ||
public @interface Order { | ||
int value() default 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API의 status를 INTERNAL로 변경하고, 주석으로 내부 사용을 위한 클래스임을 명시해주는 게 좋을 것 같습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경 완료 했습니다! 6f5e9f3