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

net.jqwik.engine.properties.arbitraries.randomized.FunctionGenerator Maven / Gradle / Ivy

The newest version!
package net.jqwik.engine.properties.arbitraries.randomized;

import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.stream.*;

import net.jqwik.api.*;
import net.jqwik.api.Tuple.*;
import net.jqwik.engine.*;
import net.jqwik.engine.support.*;

public class FunctionGenerator extends AbstractFunctionGenerator {

	private final AtomicReference> lastResult = new AtomicReference<>();

	public FunctionGenerator(
		Class functionalType,
		RandomGenerator resultGenerator,
		List>, Function, ? extends R>>> conditions
	) {
		super(functionalType, resultGenerator, conditions);
	}

	@Override
	public Shrinkable next(Random random) {
		return new ShrinkableFunction(createFunction(random));
	}

	private F createFunction(Random random) {
		long baseSeed = random.nextLong();
		InvocationHandler handler = (proxy, method, args) -> {
			if (JqwikReflectionSupport.isEqualsMethod(method)) {
				return handleEqualsMethod(proxy, args);
			}
			if (JqwikReflectionSupport.isToStringMethod(method)) {
				return handleToString(baseSeed);
			}
			if (JqwikReflectionSupport.isHashCodeMethod(method)) {
				return handleHashCode((int) baseSeed);
			}
			if (method.isDefault()) {
				return handleDefaultMethod(proxy, method, args);
			}
			return conditionalResult(args).orElseGet(() -> {
				Random randomForArgs = SourceOfRandomness.newRandom(seedForArgs(baseSeed, args));
				Shrinkable shrinkableResult = resultGenerator.next(randomForArgs);
				storeLastResult(shrinkableResult);
				return new Object[]{shrinkableResult.value()};
			})[0];
		};
		return createFunctionProxy(handler);
	}

	private int handleHashCode(final int baseSeed) {
		return baseSeed;
	}

	private Object handleToString(final long baseSeed) {
		return String.format(
			"Function<%s>(baseSeed: %s)",
			functionalType.getSimpleName(),
			baseSeed
		);
	}

	private void storeLastResult(Shrinkable result) {
		lastResult.set(result);
	}

	private long seedForArgs(long baseSeed, Object[] args) {
		long seed = baseSeed;
		if (args != null) {
			for (Object arg : args) {
				seed = Long.rotateRight(seed, 16);
				if (arg != null) {
					seed ^= arg.hashCode();
				}
			}
		}
		return seed;
	}

	private class ShrinkableFunction implements Shrinkable {

		private final F value;

		private ShrinkableFunction(F function) {
			value = function;
		}

		@Override
		public F value() {
			return value;
		}

		@Override
		public Stream> shrink() {
			if (lastResult.get() == null) {
				return Stream.empty();
			}
			Shrinkable constantFunction = createConstantFunction(lastResult.get());
			return Stream.of(constantFunction);
		}

		@Override
		public ShrinkingDistance distance() {
			return ShrinkingDistance.MAX;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy