All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jqwik.api.state.Action Maven / Gradle / Ivy

The newest version!
package net.jqwik.api.state;

import java.util.function.*;

import org.apiguardian.api.*;

import net.jqwik.api.*;

import org.jspecify.annotations.*;

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

/**
 * An action class represents a state transformation that can be performed
 * on an object of type {@code S}.
 * Those objects can be mutable, which means that the state changing method will return the same object,
 * or immutable, which requires the method to return another object that represents the transformed state.
 *
 * 

* Do not implement this interface directly, but either {@linkplain Action.Dependent} or {@linkplain Action.Independent}. * Only those can be used to create an arbitrary for a {@linkplain ActionChain}. *

* *

* Mind that there is a another interface {@link net.jqwik.api.stateful.Action} which looks similar * but refers to jqwik's old and deprecated style of state-based property testing. * The two interfaces CANNOT be used interchangeably. *

* * @param Type of the object to transform through an action * @see ActionChain * @see ActionChainArbitrary */ @API(status = EXPERIMENTAL, since = "1.7.0") public interface Action { /** * Create an unconditioned {@linkplain ActionBuilder}. */ static ActionBuilder builder() { return new ActionBuilder(); } /** * Create an {@linkplain ActionBuilder} with a precondition. */ static ActionBuilder when(Predicate precondition) { return new ActionBuilder().when(precondition); } /** * Convenience method to create an independent {@linkplain Action} with a constant transformer */ static Action.Independent just(Transformer transformer) { return Action.builder().just(transformer); } /** * Convenience method to create an independent {@linkplain Action} with a description and a constant transformer */ static Action.Independent just(String description, Transformer transformer) { return Action.builder().describeAs(description).just(transformer); } /** * If this method returns false, the action will not be performed. * *

* Implementing this method will make the chain of actions harder to shrink. *

* * @param state the current state * @return true if the precondition holds */ default boolean precondition(S state) { return true; } /** * Implement this interface if you want to have the action's transforming behaviour depend on the previous state. * *

* Implementing this interface instead of {@linkplain Independent} will make the chain of actions harder to shrink. *

*/ @FunctionalInterface interface Dependent extends Action { /** * Return an arbitrary for transformers that depends on the previous state. * *

* In addition to performing a state transformation the transformin function * can also check or assert post-conditions and invariants that should hold when doing the transformation. *

* * @param state the current state * @return an arbitrary of type {@linkplain Transformer Transformer}. */ Arbitrary> transformer(S state); } /** * Implement this interface if you want to have the action's transforming behaviour not to depend on previous state. * *

* In addition to performing a state transformation the mutator function * can also check or assert post-conditions and invariants that should hold when doing the transformation. *

* * @see JustMutate * @see JustTransform */ @FunctionalInterface interface Independent extends Action { /** * Return an arbitrary for transformers that does not depend on the previous state. * *

* In addition to performing a state transformation the transforming function * can also check or assert post-conditions and invariants that should hold when doing the transformation. *

* * @return an arbitrary of type {@linkplain Transformer Transformer}. */ Arbitrary> transformer(); } /** * Subclass if you want to implement an {@linkplain Action.Independent independent action} that simply transforms the given state. * *

* If you rather want to declaratively specify an action start with {@linkplain Action#just(Transformer)}, * {@linkplain Action#when(Predicate)} or {@linkplain Action#builder()}. *

* *

* For actions whose state transformation depends on the state, * you have to implement either {@linkplain Action.Dependent} or {@linkplain Action.Independent}. *

*/ abstract class JustTransform implements Action.Independent { @Override public Arbitrary> transformer() { return Arbitraries.just(Transformer.transform( description(), this::transform )); } public abstract S transform(S state); String description() { return getClass().getSimpleName(); } } /** * Subclass if you want to implement an {@linkplain Action.Independent independent action} that simply mutates the given state. * *

* If you rather want to declaratively specify an action start with {@linkplain Action#just(Transformer)}, * {@linkplain Action#when(Predicate)} or {@linkplain Action#builder()}. *

* *

* For actions whose state transformation depends on the state, * you have to implement either {@linkplain Action.Dependent} or {@linkplain Action.Independent}. *

*/ abstract class JustMutate implements Action.Independent { @Override public Arbitrary> transformer() { return Arbitraries.just(Transformer.mutate( description(), this::mutate )); } abstract public void mutate(S state); public String description() { return getClass().getSimpleName(); } } }