Skip to content

Commit

Permalink
Implemented JqwikSession.getRandom() and JqwikSession.start(seed)
Browse files Browse the repository at this point in the history
  • Loading branch information
jlink committed Jul 12, 2024
1 parent a502e1f commit a6dc73f
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 25 deletions.
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# 1.9.1

- JqwikSession:
- setRandomSessionSeed(), getRandomSessionSeed()
- see https://github.com/jqwik-team/jqwik/issues/581
- Document in user guide


# 1.9.x
Expand Down
41 changes: 36 additions & 5 deletions api/src/main/java/net/jqwik/api/sessions/JqwikSession.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package net.jqwik.api.sessions;

import java.util.*;

import org.apiguardian.api.*;
import org.jspecify.annotations.*;

import net.jqwik.api.*;
import net.jqwik.api.lifecycle.*;
Expand Down Expand Up @@ -30,19 +33,21 @@ public abstract static class JqwikSessionFacade {
implementation = FacadeLoader.load(JqwikSession.JqwikSessionFacade.class);
}

public abstract void startSession();

public abstract void finishSession();

public abstract void finishTry();

public abstract boolean isSessionOpen();

public abstract void runInSession(Runnable runnable);
public abstract void runInSession(@Nullable String randomSeed, Runnable runnable);

public abstract Optional<Random> getRandom();

public abstract void startSession(@Nullable String randomSeed);
}

public synchronized static void start() {
JqwikSessionFacade.implementation.startSession();
JqwikSessionFacade.implementation.startSession(null);
}

public static boolean isActive() {
Expand All @@ -58,8 +63,34 @@ public synchronized static void finishTry() {
}

public synchronized static void run(Runnable runnable) {
JqwikSessionFacade.implementation.runInSession(runnable);
JqwikSessionFacade.implementation.runInSession(null, runnable);
}

/**
* Returns the {@linkplain Random} instance associated with the current session.
* @return a Random instance if a session is active, otherwise an empty Optional
*/
@API(status = EXPERIMENTAL, since = "1.9.1")
public static Optional<Random> getRandom() {
return JqwikSessionFacade.implementation.getRandom();
}

/**
* Starts a new session with a given random seed.
* Currently seeds must be strings that can be parsed by {@linkplain Long#parseLong(String)}.
*/
@API(status = EXPERIMENTAL, since = "1.9.1")
public static void start(String randomSeed) {
JqwikSessionFacade.implementation.startSession(randomSeed);
}

/**
* Runs a given {@linkplain Runnable} in a new session with a given random seed.
* Currently seeds must be strings that can be parsed by {@linkplain Long#parseLong(String)}.
*/
@API(status = EXPERIMENTAL, since = "1.9.1")
public static void run(String randomSeed, Runnable runnable) {
JqwikSessionFacade.implementation.runInSession(randomSeed, runnable);
}

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package net.jqwik.engine.facades;

import java.util.*;
import java.util.logging.*;

import org.jspecify.annotations.*;
import org.junit.platform.engine.*;
import org.junit.platform.engine.support.descriptor.*;

import net.jqwik.api.*;
import net.jqwik.api.sessions.*;
import net.jqwik.engine.*;
import net.jqwik.engine.execution.lifecycle.*;
import net.jqwik.engine.support.*;

Expand All @@ -29,18 +32,6 @@ public Type getType() {
}
};

@Override
public void startSession() {
if (!CurrentTestDescriptor.isEmpty()) {
if (CurrentTestDescriptor.get() == SESSION_DESCRIPTOR) {
throw new JqwikException("JqwikSession.start() cannot be nested");
} else {
throw new JqwikException("JqwikSession.start() must only be used outside jqwik's standard lifecycle");
}
}
CurrentTestDescriptor.push(SESSION_DESCRIPTOR);
}

@Override
public void finishSession() {
if (!isSessionOpen()) {
Expand All @@ -65,8 +56,11 @@ public boolean isSessionOpen() {
}

@Override
public void runInSession(JqwikSession.Runnable runnable) {
public void runInSession(@Nullable String randomSeed, JqwikSession.Runnable runnable) {
try {
if (randomSeed != null) {
SourceOfRandomness.create(randomSeed);
}
JqwikSession.start();
runnable.run();
} catch (Throwable t) {
Expand All @@ -81,4 +75,33 @@ private void finishSessionLifecycle() {
StoreRepository.getCurrent().finishProperty(SESSION_DESCRIPTOR);
StoreRepository.getCurrent().finishScope(SESSION_DESCRIPTOR);
}

@Override
public Optional<Random> getRandom() {
if (!isSessionOpen()) {
return Optional.empty();
}
return Optional.of(SourceOfRandomness.current());
}

@Override
public void startSession(@Nullable String randomSeed) {
if (randomSeed != null) {
SourceOfRandomness.create(randomSeed);
}
startSession();
}

private void startSession() {
if (!CurrentTestDescriptor.isEmpty()) {
if (CurrentTestDescriptor.get() == SESSION_DESCRIPTOR) {
throw new JqwikException("JqwikSession.start() cannot be nested");
} else {
throw new JqwikException("JqwikSession.start() must only be used outside jqwik's standard lifecycle");
}
}
CurrentTestDescriptor.push(SESSION_DESCRIPTOR);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.junit.jupiter.api.*;

import net.jqwik.api.*;
import net.jqwik.api.Disabled;
import net.jqwik.api.arbitraries.*;
import net.jqwik.api.lifecycle.*;
import net.jqwik.api.providers.*;
Expand Down Expand Up @@ -182,13 +181,69 @@ void runInSession() {
}

@Test
@Disabled("Not implemented yet")
void startWithRandomSeed() {
// JqwikSession.start("1234");
// or
// JqwikSession.run("1234", () -> { ... });
void inactiveSessionHasNoRandom() {
assertThat(JqwikSession.getRandom()).isEmpty();
}

@Test
void accessRandomInActiveSession() {
JqwikSession.start();
Optional<Random> optionalRandom = JqwikSession.getRandom();
assertThat(optionalRandom).isPresent();
Random random = optionalRandom.get();
assertThat(random.nextInt()).isNotZero();

// Trigger some random generation
assertThat(
Arbitraries.strings().sampleStream().limit(5)
).hasSize(5);

assertThat(JqwikSession.getRandom()).hasValue(random);
}

@Test
void startSessionWithGivenRandomSeed() {
Arbitrary<String> strings = Arbitraries.strings().alpha().ofMaxLength(5);

JqwikSession.start("42");
List<String> generatedValues = strings.sampleStream().limit(10).collect(Collectors.toList());
JqwikSession.finish();

JqwikSession.start("42");
assertThat(strings.sampleStream().limit(10).collect(Collectors.toList()))
.isEqualTo(generatedValues);
JqwikSession.finish();

JqwikSession.start("4242");
assertThat(strings.sampleStream().limit(10).collect(Collectors.toList()))
.isNotEqualTo(generatedValues);
JqwikSession.finish();
}

@Test
void runInSessionWithGivenRandomSeed() {
Arbitrary<String> strings = Arbitraries.strings().alpha().ofMaxLength(5);
List<String> generatedValues = new ArrayList<>();

JqwikSession.run("42", () -> {
strings.sampleStream().limit(10).forEach(generatedValues::add);
});

JqwikSession.run("42", () -> {
assertThat(
strings.sampleStream().limit(10).collect(Collectors.toList())
).isEqualTo(generatedValues);
});

JqwikSession.run("4243", () -> {
assertThat(
strings.sampleStream().limit(10).collect(Collectors.toList())
).isNotEqualTo(generatedValues);
});
}



}

private static class PersonProvider implements ArbitraryProvider {
Expand Down

0 comments on commit a6dc73f

Please sign in to comment.