Skip to content

Commit ae4872d

Browse files
committed
Fix the seed option to apply per FixtureMonkey instance.
1 parent fd15d9a commit ae4872d

File tree

11 files changed

+198
-64
lines changed

11 files changed

+198
-64
lines changed

docs/content/v1.1.x-kor/release-notes/_index.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ sectionStart
99
## v.1.1.4
1010
Fix not registering size API if decomposing.
1111

12+
Fix the `seed` option to apply per `FixtureMonkey` instance.
13+
1214
sectionEnd
1315

1416
sectionStart

docs/content/v1.1.x/release-notes/_index.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ sectionStart
99
## v.1.1.4
1010
Fix not registering size API if decomposing.
1111

12+
Fix the `seed` option to apply per `FixtureMonkey` instance.
13+
1214
sectionEnd
1315

1416
sectionStart

fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/context/MonkeyContext.java

+12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.List;
2424
import java.util.TreeMap;
2525

26+
import javax.annotation.Nullable;
27+
2628
import org.apiguardian.api.API;
2729
import org.apiguardian.api.API.Status;
2830

@@ -50,19 +52,24 @@ public final class MonkeyContext {
5052
private final ConcurrentLruCache<Property, CombinableArbitrary<?>> javaArbitrariesByProperty;
5153
private final ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty;
5254
private final List<MatcherOperator<? extends ObjectBuilder<?>>> registeredArbitraryBuilders;
55+
56+
@Nullable
57+
private final Long seed;
5358
private final FixtureMonkeyOptions fixtureMonkeyOptions;
5459

5560
public MonkeyContext(
5661
ConcurrentLruCache<Property, CombinableArbitrary<?>> arbitrariesByProperty,
5762
ConcurrentLruCache<Property, CombinableArbitrary<?>> javaArbitrariesByProperty,
5863
ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty,
5964
List<MatcherOperator<? extends ObjectBuilder<?>>> registeredArbitraryBuilders,
65+
@Nullable Long seed,
6066
FixtureMonkeyOptions fixtureMonkeyOptions
6167
) {
6268
this.arbitrariesByProperty = arbitrariesByProperty;
6369
this.javaArbitrariesByProperty = javaArbitrariesByProperty;
6470
this.generatorContextByRootProperty = generatorContextByRootProperty;
6571
this.registeredArbitraryBuilders = registeredArbitraryBuilders;
72+
this.seed = seed;
6673
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
6774
}
6875

@@ -101,6 +108,11 @@ public List<MatcherOperator<? extends ObjectBuilder<?>>> getRegisteredArbitraryB
101108
return registeredArbitraryBuilders;
102109
}
103110

111+
@Nullable
112+
public Long getSeed() {
113+
return seed;
114+
}
115+
104116
public FixtureMonkeyOptions getFixtureMonkeyOptions() {
105117
return fixtureMonkeyOptions;
106118
}

fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/context/MonkeyContextBuilder.java

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.ArrayList;
2222
import java.util.List;
2323

24+
import javax.annotation.Nullable;
25+
2426
import org.apiguardian.api.API;
2527
import org.apiguardian.api.API.Status;
2628

@@ -42,6 +44,8 @@ public final class MonkeyContextBuilder {
4244
private List<MatcherOperator<? extends ObjectBuilder<?>>> registeredObjectBuilders;
4345
private int cacheSize = 2048;
4446
private int generatorContextSize = 1000;
47+
@Nullable
48+
private Long seed = null;
4549

4650
public MonkeyContextBuilder(FixtureMonkeyOptions fixtureMonkeyOptions) {
4751
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
@@ -85,6 +89,11 @@ public MonkeyContextBuilder registeredObjectBuilder(
8589
return this;
8690
}
8791

92+
public MonkeyContextBuilder seed(@Nullable Long seed) {
93+
this.seed = seed;
94+
return this;
95+
}
96+
8897
public MonkeyContext build() {
8998
if (arbitrariesByProperty == null) {
9099
arbitrariesByProperty = new ConcurrentLruCache<>(cacheSize);
@@ -107,6 +116,7 @@ public MonkeyContext build() {
107116
javaArbitrariesByProperty,
108117
generatorContextByRootProperty,
109118
registeredObjectBuilders,
119+
seed,
110120
fixtureMonkeyOptions
111121
);
112122
}

fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/random/Randoms.java

+26-11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import java.util.Random;
2222

23+
import javax.annotation.Nullable;
24+
2325
import org.apiguardian.api.API;
2426
import org.apiguardian.api.API.Status;
2527

@@ -28,6 +30,8 @@
2830

2931
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
3032

33+
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache;
34+
3135
/**
3236
* Reference jqwik SourceOfRandomness
3337
*/
@@ -37,6 +41,7 @@ public abstract class Randoms {
3741
private static final boolean USE_JQWIK_ENGINE;
3842
private static final ThreadLocal<Random> CURRENT = new ThreadLocal<>();
3943
private static final ThreadLocal<Long> SEED = new ThreadLocal<>();
44+
private static final ConcurrentLruCache<Long, Random> CACHED_SEED = new ConcurrentLruCache<>(5);
4045

4146
static {
4247
boolean useJqwikEngine;
@@ -50,20 +55,24 @@ public abstract class Randoms {
5055
}
5156

5257
public static Random create(String seed) {
53-
if (USE_JQWIK_ENGINE) {
54-
SEED.set(Long.parseLong(seed));
55-
return SourceOfRandomness.create(seed);
56-
}
57-
58+
long longSeed;
5859
try {
59-
long actualSeed = Long.parseLong(seed);
60-
Random random = newRandom(actualSeed);
61-
CURRENT.set(random);
62-
SEED.set(actualSeed);
63-
return random;
60+
longSeed = Long.parseLong(seed);
6461
} catch (NumberFormatException nfe) {
6562
throw new JqwikException(String.format("[%s] is not a valid random seed.", seed));
6663
}
64+
65+
return CACHED_SEED.computeIfAbsent(longSeed, l -> {
66+
if (USE_JQWIK_ENGINE) {
67+
SEED.set(longSeed);
68+
return SourceOfRandomness.create(seed);
69+
}
70+
71+
Random random = newRandom(longSeed);
72+
CURRENT.set(random);
73+
SEED.set(longSeed);
74+
return random;
75+
});
6776
}
6877

6978
public static Random current() {
@@ -72,14 +81,20 @@ public static Random current() {
7281
: CURRENT.get();
7382
}
7483

75-
public static long currentSeed() {
84+
@Nullable
85+
public static Long currentSeed() {
7686
return SEED.get();
7787
}
7888

7989
public static int nextInt(int bound) {
8090
return current().nextInt(bound);
8191
}
8292

93+
public static void clear() {
94+
SEED.remove();
95+
CURRENT.remove();
96+
}
97+
8398
private static Random newRandom(final long seed) {
8499
return USE_JQWIK_ENGINE
85100
? SourceOfRandomness.newRandom(seed)

fixture-monkey-junit-jupiter/src/main/java/com/navercorp/fixturemonkey/junit/jupiter/extension/FixtureMonkeySeedExtension.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import java.lang.reflect.Method;
2121

22+
import javax.annotation.Nullable;
23+
2224
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
2325
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
2426
import org.junit.jupiter.api.extension.ExtensionContext;
@@ -30,10 +32,12 @@
3032

3133
public final class FixtureMonkeySeedExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
3234
private static final Logger LOGGER = LoggerFactory.getLogger(FixtureMonkeySeedExtension.class);
35+
private final ThreadLocal<Long> previousSeed = new ThreadLocal<>();
3336

3437
@Override
3538
public void beforeTestExecution(ExtensionContext context) throws Exception {
3639
Seed seed = context.getRequiredTestMethod().getAnnotation(Seed.class);
40+
previousSeed.set(Randoms.currentSeed());
3741
if (seed != null) {
3842
setSeed(seed.value());
3943
}
@@ -49,13 +53,19 @@ public void afterTestExecution(ExtensionContext context) throws Exception {
4953
if (context.getExecutionException().isPresent()) {
5054
logSeedIfTestFailed(context);
5155
}
56+
57+
setSeed(previousSeed.get());
5258
}
5359

5460
/**
5561
* Sets the seed for generating random numbers.
5662
**/
57-
private void setSeed(long seed) {
58-
Randoms.create(String.valueOf(seed));
63+
private void setSeed(@Nullable Long seed) {
64+
if (seed == null) {
65+
Randoms.clear();
66+
} else {
67+
Randoms.create(String.valueOf(seed));
68+
}
5969
}
6070

6171
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Fixture Monkey
3+
*
4+
* Copyright (c) 2021-present NAVER Corp.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package com.navercorp.fixturemonkey.junit.jupiter.extension
20+
21+
import com.navercorp.fixturemonkey.FixtureMonkey
22+
import com.navercorp.fixturemonkey.api.random.Randoms
23+
import com.navercorp.fixturemonkey.junit.jupiter.annotation.Seed
24+
import org.assertj.core.api.BDDAssertions.then
25+
import org.junit.jupiter.api.Test
26+
import org.junit.jupiter.api.extension.ExtendWith
27+
28+
@ExtendWith(FixtureMonkeySeedExtension::class)
29+
class FixtureMonkeySeedTest {
30+
@Test
31+
fun withoutSeedAnnotationApplyNull() {
32+
then(Randoms.currentSeed()).isNull()
33+
}
34+
35+
@Test
36+
@Seed(1000L)
37+
fun seedAnnotation() {
38+
then(Randoms.currentSeed()).isEqualTo(1000L)
39+
}
40+
41+
companion object {
42+
private val FIXTURE_MONKEY = FixtureMonkey.builder()
43+
.seed(12345L)
44+
.build()
45+
}
46+
}

fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ public FixtureMonkey(
5757
FixtureMonkeyOptions fixtureMonkeyOptions,
5858
ManipulatorOptimizer manipulatorOptimizer,
5959
List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> registeredArbitraryBuilders,
60+
MonkeyContext monkeyContext,
6061
MonkeyManipulatorFactory monkeyManipulatorFactory
6162
) {
6263
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
6364
this.manipulatorOptimizer = manipulatorOptimizer;
64-
this.monkeyContext = MonkeyContext.builder(fixtureMonkeyOptions).build();
6565
this.monkeyManipulatorFactory = monkeyManipulatorFactory;
66+
this.monkeyContext = monkeyContext;
6667
initializeRegisteredArbitraryBuilders(registeredArbitraryBuilders);
6768
}
6869

fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import com.navercorp.fixturemonkey.api.constraint.JavaConstraintGenerator;
3434
import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory;
35+
import com.navercorp.fixturemonkey.api.context.MonkeyContext;
3536
import com.navercorp.fixturemonkey.api.generator.ArbitraryContainerInfoGenerator;
3637
import com.navercorp.fixturemonkey.api.generator.ArbitraryGenerator;
3738
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGenerator;
@@ -51,7 +52,6 @@
5152
import com.navercorp.fixturemonkey.api.plugin.Plugin;
5253
import com.navercorp.fixturemonkey.api.property.PropertyGenerator;
5354
import com.navercorp.fixturemonkey.api.property.PropertyNameResolver;
54-
import com.navercorp.fixturemonkey.api.random.Randoms;
5555
import com.navercorp.fixturemonkey.api.type.Types;
5656
import com.navercorp.fixturemonkey.api.validator.ArbitraryValidator;
5757
import com.navercorp.fixturemonkey.buildergroup.ArbitraryBuilderCandidate;
@@ -487,10 +487,6 @@ public FixtureMonkeyBuilder pushCustomizeValidOnly(TreeMatcher matcher, boolean
487487
return this;
488488
}
489489

490-
/**
491-
* It is deprecated. Please use {@code @Seed} in fixture-monkey-junit-jupiter module.
492-
*/
493-
@Deprecated
494490
public FixtureMonkeyBuilder seed(long seed) {
495491
this.seed = seed;
496492
return this;
@@ -504,11 +500,15 @@ public FixtureMonkey build() {
504500
fixtureMonkeyOptions.getDecomposedContainerValueFactory()
505501
);
506502

507-
Randoms.create(String.valueOf(seed));
503+
MonkeyContext monkeyContext = MonkeyContext.builder(fixtureMonkeyOptions)
504+
.seed(seed)
505+
.build();
506+
508507
return new FixtureMonkey(
509508
fixtureMonkeyOptions,
510509
manipulatorOptimizer,
511510
registeredArbitraryBuilders,
511+
monkeyContext,
512512
monkeyManipulatorFactory
513513
);
514514
}

fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ public CombinableArbitrary<?> resolve(
9999
},
100100
fixtureMonkeyOptions.getGenerateMaxTries(),
101101
fixtureMonkeyOptions.getDefaultArbitraryValidator(),
102-
builderContext::isValidOnly
102+
builderContext::isValidOnly,
103+
monkeyContext
103104
);
104105
}
105106
}

0 commit comments

Comments
 (0)