package br.com.six2six.fixturefactory.function.impl; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; import java.math.RoundingMode; import java.util.Random; import br.com.six2six.fixturefactory.base.Range; import br.com.six2six.fixturefactory.function.AtomicFunction; public class RandomFunction implements AtomicFunction { private Class<?> type; private Object[] dataset; private AtomicFunction[] functions; private Range range; private MathContext mathContext = MathContext.DECIMAL32; public RandomFunction(Class<?> type) { this.type = type; } public RandomFunction(Object[] dataset) { this.dataset = dataset; } public RandomFunction(AtomicFunction[] functions) { this.functions = functions; } public RandomFunction(Class<?> type, Object[] dataset) { this.type = type; this.dataset = dataset; } public RandomFunction(Class<?> type, Range range) { this.type = type; this.range = range; } public RandomFunction(Class<? extends BigDecimal> type, MathContext mathContext) { this.type = type; this.mathContext = mathContext; } @Override @SuppressWarnings("unchecked") public <T> T generateValue() { Object result = null; Random random = new Random(); if (this.dataset != null && this.dataset.length > 0) { result = this.dataset[random.nextInt(this.dataset.length)]; } else if (this.functions != null && this.functions.length > 0) { result = this.functions[random.nextInt(this.functions.length)].generateValue(); } else if (this.type.isEnum()) { result = this.type.getEnumConstants()[random.nextInt(this.type.getEnumConstants().length)]; } else if (this.type.isAssignableFrom(Byte.class)) { result = this.range == null ? (byte) random.nextInt(Byte.MAX_VALUE + 1) : (byte) getRandomLong(this.range); } else if (this.type.isAssignableFrom(Short.class)) { result = this.range == null ? (short) random.nextInt(Short.MAX_VALUE + 1) : (short) getRandomLong(this.range); } else if (this.type.isAssignableFrom(Integer.class)) { result = this.range == null ? random.nextInt() : (int) getRandomLong(this.range); } else if (this.type.isAssignableFrom(Long.class)) { result = this.range == null ? random.nextLong() : getRandomLong(this.range); } else if (this.type.isAssignableFrom(Float.class)) { result = this.range == null ? random.nextFloat() : (float) getRandomDouble(this.range); } else if (this.type.isAssignableFrom(Double.class)) { result = this.range == null ? random.nextDouble() : getRandomDouble(this.range); } else if (this.type.isAssignableFrom(Boolean.class)) { result = random.nextBoolean(); } else if (this.type.isAssignableFrom(BigDecimal.class)) { if (this.range == null) { result = new BigDecimal(random.nextDouble(), this.mathContext); } else { result = getRandomBigDecimalByRange(); } } else if (this.type.isAssignableFrom(BigInteger.class)) { if (this.range == null) { result = new BigInteger(64, random); } else { result = getRandomBigDecimalByRange().toBigInteger(); } } return (T) result; } private long getRandomLong(Range range) { return Math.round(getRandomDouble(range)); } private double getRandomDouble(Range range) { return range.getStart().doubleValue() + (Math.random() * (range.getEnd().doubleValue() - range.getStart().doubleValue())); } private BigDecimal getRandomBigDecimal(BigDecimal start, BigDecimal end) { int scale = start.scale() > end.scale() ? start.scale() : end.scale(); return start.add(new BigDecimal(Math.random()).multiply(end.subtract(start))).setScale(scale, RoundingMode.HALF_EVEN); } private BigDecimal getRandomBigDecimalByRange() { final BigDecimal start = new BigDecimal(this.range.getStart().toString()); final BigDecimal end = new BigDecimal(this.range.getEnd().toString()); return getRandomBigDecimal(start, end); } }