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

net.jqwik.api.lifecycle.PerProperty Maven / Gradle / Ivy

There is a newer version: 1.9.2
Show newest version
package net.jqwik.api.lifecycle;

import java.lang.annotation.*;
import java.util.*;

import org.apiguardian.api.*;

import net.jqwik.api.*;
import net.jqwik.api.lifecycle.ResolveParameterHook.*;

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

/**
 * Annotate property methods of a container class with {@code @PerProperty}
 * if you want to have some lifecycle control over this property alone.
 *
 * 

* If you want to control the lifecycle of all property methods use * {@linkplain BeforeProperty} or {@linkplain AfterProperty}. *

*/ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @AddLifecycleHook(PerProperty.PerPropertyHook.class) @API(status = EXPERIMENTAL, since = "1.2.4") public @interface PerProperty { interface Lifecycle { /** * Override if you want to provide parameters for this property. * * @param parameterContext The object to retrieve information about the parameter to resolve * @return a supplier wrapped in {@code Optional.of()} */ default Optional resolve(ParameterResolutionContext parameterContext) { return Optional.empty(); } /** * Override if you want to perform some work once before the annotated property (or example). * * @param context The object to retrieve information about the current property */ default void before(PropertyLifecycleContext context) {} /** * Override if you want to perform some work once after the annotated property (or example). * * @param propertyExecutionResult The object to retrieve information about the property's execution result */ default void after(PropertyExecutionResult propertyExecutionResult) {} /** * Override if you want to perform some work or run assertions if - and only if - the property succeeded. * If you want to make the property fail just use an appropriate assertion methods or throw an exception. */ default void onSuccess() {} /** * Override if you want to perform some work or run assertions if - and only if - the property failed. * You have to return the original {@code propertyExecutionResult} or transform it into another result. * * @param propertyExecutionResult The object that represents the property's execution result */ default PropertyExecutionResult onFailure(PropertyExecutionResult propertyExecutionResult) { return propertyExecutionResult; } } /** * Return a class that implements {@linkplain Lifecycle} * * @return An implementation of {@linkplain Lifecycle} */ Class value(); class PerPropertyHook implements AroundPropertyHook, ResolveParameterHook { private Lifecycle lifecycle(LifecycleContext context) { return Store.getOrCreate("lifecycle", Lifespan.PROPERTY, () -> createLifecycleInstance(context)).get(); } private Lifecycle createLifecycleInstance(LifecycleContext context) { Optional perProperty = context.findAnnotation(PerProperty.class); Class lifecycleClass = perProperty.map(PerProperty::value).orElseThrow(() -> { String message = "@PerProperty annotation MUST have a value() attribute"; return new JqwikException(message); }); return context.newInstance(lifecycleClass); } @Override public PropertyExecutionResult aroundProperty(PropertyLifecycleContext context, PropertyExecutor property) { Lifecycle lifecycle = lifecycle(context); runBeforeExecutionLifecycles(context, lifecycle); PropertyExecutionResult executionResult = property.execute(); return runAfterExecutionLifecycles(lifecycle, executionResult); } private void runBeforeExecutionLifecycles(PropertyLifecycleContext context, Lifecycle lifecycle) { lifecycle.before(context); } private PropertyExecutionResult runAfterExecutionLifecycles( Lifecycle lifecycle, PropertyExecutionResult executionResult ) { try { if (executionResult.status() == PropertyExecutionResult.Status.SUCCESSFUL) { try { lifecycle.onSuccess(); } catch (Throwable throwable) { return executionResult.mapToFailed(throwable); } } else if (executionResult.status() == PropertyExecutionResult.Status.FAILED) { return lifecycle.onFailure(executionResult); } return executionResult; } finally { lifecycle.after(executionResult); } } @Override public int aroundPropertyProximity() { // Somewhat closer than standard hooks return 10; } @Override public Optional resolve(ParameterResolutionContext parameterContext, LifecycleContext lifecycleContext) { return lifecycle(lifecycleContext).resolve(parameterContext); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy