Skip to content
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

Fix the seed option to apply per FixtureMonkey instance. #1109

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/content/v1.1.x-kor/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ sectionStart
## v.1.1.4
Fix not registering size API if decomposing.

Fix the `seed` option to apply per `FixtureMonkey` instance.

sectionEnd

sectionStart
Expand Down
2 changes: 2 additions & 0 deletions docs/content/v1.1.x/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ sectionStart
## v.1.1.4
Fix not registering size API if decomposing.

Fix the `seed` option to apply per `FixtureMonkey` instance.

sectionEnd

sectionStart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.util.List;
import java.util.TreeMap;

import javax.annotation.Nullable;

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

Expand Down Expand Up @@ -50,19 +52,24 @@ public final class MonkeyContext {
private final ConcurrentLruCache<Property, CombinableArbitrary<?>> javaArbitrariesByProperty;
private final ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty;
private final List<MatcherOperator<? extends ObjectBuilder<?>>> registeredArbitraryBuilders;

@Nullable
private final Long seed;
private final FixtureMonkeyOptions fixtureMonkeyOptions;

public MonkeyContext(
ConcurrentLruCache<Property, CombinableArbitrary<?>> arbitrariesByProperty,
ConcurrentLruCache<Property, CombinableArbitrary<?>> javaArbitrariesByProperty,
ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty,
List<MatcherOperator<? extends ObjectBuilder<?>>> registeredArbitraryBuilders,
@Nullable Long seed,
FixtureMonkeyOptions fixtureMonkeyOptions
) {
this.arbitrariesByProperty = arbitrariesByProperty;
this.javaArbitrariesByProperty = javaArbitrariesByProperty;
this.generatorContextByRootProperty = generatorContextByRootProperty;
this.registeredArbitraryBuilders = registeredArbitraryBuilders;
this.seed = seed;
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
}

Expand Down Expand Up @@ -101,6 +108,11 @@ public List<MatcherOperator<? extends ObjectBuilder<?>>> getRegisteredArbitraryB
return registeredArbitraryBuilders;
}

@Nullable
public Long getSeed() {
return seed;
}

public FixtureMonkeyOptions getFixtureMonkeyOptions() {
return fixtureMonkeyOptions;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nullable;

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

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

public MonkeyContextBuilder(FixtureMonkeyOptions fixtureMonkeyOptions) {
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
Expand Down Expand Up @@ -85,6 +89,11 @@ public MonkeyContextBuilder registeredObjectBuilder(
return this;
}

public MonkeyContextBuilder seed(@Nullable Long seed) {
this.seed = seed;
return this;
}

public MonkeyContext build() {
if (arbitrariesByProperty == null) {
arbitrariesByProperty = new ConcurrentLruCache<>(cacheSize);
Expand All @@ -107,6 +116,7 @@ public MonkeyContext build() {
javaArbitrariesByProperty,
generatorContextByRootProperty,
registeredObjectBuilders,
seed,
fixtureMonkeyOptions
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import java.util.Random;

import javax.annotation.Nullable;

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

Expand All @@ -28,6 +30,8 @@

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

import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache;

/**
* Reference jqwik SourceOfRandomness
*/
Expand All @@ -37,6 +41,7 @@ public abstract class Randoms {
private static final boolean USE_JQWIK_ENGINE;
private static final ThreadLocal<Random> CURRENT = new ThreadLocal<>();
private static final ThreadLocal<Long> SEED = new ThreadLocal<>();
private static final ConcurrentLruCache<Long, Random> CACHED_SEED = new ConcurrentLruCache<>(5);

static {
boolean useJqwikEngine;
Expand All @@ -50,20 +55,24 @@ public abstract class Randoms {
}

public static Random create(String seed) {
if (USE_JQWIK_ENGINE) {
SEED.set(Long.parseLong(seed));
return SourceOfRandomness.create(seed);
}

long longSeed;
try {
long actualSeed = Long.parseLong(seed);
Random random = newRandom(actualSeed);
CURRENT.set(random);
SEED.set(actualSeed);
return random;
longSeed = Long.parseLong(seed);
} catch (NumberFormatException nfe) {
throw new JqwikException(String.format("[%s] is not a valid random seed.", seed));
}

return CACHED_SEED.computeIfAbsent(longSeed, l -> {
if (USE_JQWIK_ENGINE) {
SEED.set(longSeed);
return SourceOfRandomness.create(seed);
}

Random random = newRandom(longSeed);
CURRENT.set(random);
SEED.set(longSeed);
return random;
});
}

public static Random current() {
Expand All @@ -72,14 +81,20 @@ public static Random current() {
: CURRENT.get();
}

public static long currentSeed() {
@Nullable
public static Long currentSeed() {
return SEED.get();
}

public static int nextInt(int bound) {
return current().nextInt(bound);
}

public static void clear() {
SEED.remove();
CURRENT.remove();
}

private static Random newRandom(final long seed) {
return USE_JQWIK_ENGINE
? SourceOfRandomness.newRandom(seed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import java.lang.reflect.Method;

import javax.annotation.Nullable;

import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
Expand All @@ -30,10 +32,12 @@

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

@Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
Seed seed = context.getRequiredTestMethod().getAnnotation(Seed.class);
previousSeed.set(Randoms.currentSeed());
if (seed != null) {
setSeed(seed.value());
}
Expand All @@ -49,13 +53,19 @@ public void afterTestExecution(ExtensionContext context) throws Exception {
if (context.getExecutionException().isPresent()) {
logSeedIfTestFailed(context);
}

setSeed(previousSeed.get());
}

/**
* Sets the seed for generating random numbers.
**/
private void setSeed(long seed) {
Randoms.create(String.valueOf(seed));
private void setSeed(@Nullable Long seed) {
if (seed == null) {
Randoms.clear();
} else {
Randoms.create(String.valueOf(seed));
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.junit.jupiter.extension

import com.navercorp.fixturemonkey.FixtureMonkey
import com.navercorp.fixturemonkey.api.random.Randoms
import com.navercorp.fixturemonkey.junit.jupiter.annotation.Seed
import org.assertj.core.api.BDDAssertions.then
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(FixtureMonkeySeedExtension::class)
class FixtureMonkeySeedTest {
@Test
fun withoutSeedAnnotationApplyNull() {
then(Randoms.currentSeed()).isNull()
}

@Test
@Seed(1000L)
fun seedAnnotation() {
then(Randoms.currentSeed()).isEqualTo(1000L)
}

companion object {
private val FIXTURE_MONKEY = FixtureMonkey.builder()
.seed(12345L)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ public FixtureMonkey(
FixtureMonkeyOptions fixtureMonkeyOptions,
ManipulatorOptimizer manipulatorOptimizer,
List<MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> registeredArbitraryBuilders,
MonkeyContext monkeyContext,
MonkeyManipulatorFactory monkeyManipulatorFactory
) {
this.fixtureMonkeyOptions = fixtureMonkeyOptions;
this.manipulatorOptimizer = manipulatorOptimizer;
this.monkeyContext = MonkeyContext.builder(fixtureMonkeyOptions).build();
this.monkeyManipulatorFactory = monkeyManipulatorFactory;
this.monkeyContext = monkeyContext;
initializeRegisteredArbitraryBuilders(registeredArbitraryBuilders);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

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.generator.ArbitraryContainerInfoGenerator;
import com.navercorp.fixturemonkey.api.generator.ArbitraryGenerator;
import com.navercorp.fixturemonkey.api.generator.ContainerPropertyGenerator;
Expand All @@ -51,7 +52,6 @@
import com.navercorp.fixturemonkey.api.plugin.Plugin;
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;
Expand Down Expand Up @@ -487,10 +487,6 @@ public FixtureMonkeyBuilder pushCustomizeValidOnly(TreeMatcher matcher, boolean
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;
Expand All @@ -504,11 +500,15 @@ public FixtureMonkey build() {
fixtureMonkeyOptions.getDecomposedContainerValueFactory()
);

Randoms.create(String.valueOf(seed));
MonkeyContext monkeyContext = MonkeyContext.builder(fixtureMonkeyOptions)
.seed(seed)
.build();

return new FixtureMonkey(
fixtureMonkeyOptions,
manipulatorOptimizer,
registeredArbitraryBuilders,
monkeyContext,
monkeyManipulatorFactory
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public CombinableArbitrary<?> resolve(
},
fixtureMonkeyOptions.getGenerateMaxTries(),
fixtureMonkeyOptions.getDefaultArbitraryValidator(),
builderContext::isValidOnly
builderContext::isValidOnly,
monkeyContext
);
}
}
Loading