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

autofixture.generators.numbers.RandomNumberGenerator Maven / Gradle / Ivy

package autofixture.generators.numbers;

import autofixture.exceptions.ObjectCreationException;
import autofixture.interfaces.FixtureContract;
import autofixture.interfaces.InstanceGenerator;
import autofixture.interfaces.InstanceType;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.*;

/**
 * Ported from https://github.com/AutoFixture/AutoFixture
 */

public class RandomNumberGenerator implements InstanceGenerator {
  public static final int SIZE_OF_INT_64_IN_BYTES = 8;
  private final List limits;
  private final Object syncRoot;
  private final Random random;
  private final Set numbers;
  private long lower;
  private long upper;
  private long count;


  public RandomNumberGenerator() {
    this(Lists.newArrayList(
        Long.valueOf(1),
        Long.valueOf(Byte.MAX_VALUE),
        Long.valueOf(Short.MAX_VALUE),
        Long.valueOf(Integer.MAX_VALUE)));
  }

  public RandomNumberGenerator(final List limits) {
    if (limits == null) {
      throw new NullPointerException("limits");
    }

    if (limits.size() < 2) {
      throw new IllegalArgumentException("The limit must be a sequence of two or more integers.");
    }

    this.limits = limits;
    this.syncRoot = new Object();
    this.random = new Random();
    this.numbers = new HashSet<>();
    this.createRange();
  }

  public Iterable getLimits() {
    return this.limits;
  }

  private Long getNextRandom() {
    synchronized (this.syncRoot) {
      this.evaluateRange();

      long result;
      do {
        if (this.lower >= Integer.MIN_VALUE && this.upper <= Integer.MAX_VALUE) {
          result = this.random.nextInt((int) this.upper - (int) this.lower) + (int) this.lower;
        } else {
          result = this.getNextInt64InRange();
        }
      }
      while (this.numbers.contains(result));

      this.numbers.add(result);
      return result;
    }
  }

  private void evaluateRange() {
    if (this.count == this.upper - this.lower) {
      this.count = 0;
      this.createRange();
    }

    this.count++;
  }

  private void createRange() {
    final Collection remaining = Collections2.filter(this.limits, x -> x > upper - 1);

    if (remaining.size() > 0 && this.numbers.size() > 0) {
      this.lower = this.upper;
      this.upper = Ordering.natural().min(remaining) + 1;
    } else {
      this.lower = limits.get(0);
      this.upper = limits.get(1);
    }

    this.numbers.clear();
  }

  private long getNextInt64InRange() {
    final long range = this.upper - this.lower;
    final long limit = Long.MAX_VALUE - Long.MAX_VALUE % range;
    long number;
    do {
      final byte[] buffer = new byte[SIZE_OF_INT_64_IN_BYTES];
      this.random.nextBytes(buffer);
      number = bytesToLong(buffer);
    } while (number > limit);
    return number % range + this.lower;
  }

  @Override
  public  boolean appliesTo(final InstanceType instanceType) {
    return instanceType.isCompatibleWithAnyOf(
        Byte.class,
        Character.class,
        Integer.class,
        Long.class,
        Short.class);
  }

  @Override
  public  T next(final InstanceType instanceType, final FixtureContract fixture) {
    try {
      if (instanceType.isCompatibleWith(Integer.class)) {
        return (T) Integer.valueOf(this.getNextRandom().intValue());
      } else if (instanceType.isCompatibleWith(Short.class)) {
        return (T) Short.valueOf(getNextRandom().shortValue());
      } else if (instanceType.isCompatibleWith(Long.class)) {
        return (T) getNextRandom();
      } else if (instanceType.isCompatibleWith(Byte.class)) {
        return (T) Byte.valueOf(getNextRandom().byteValue());
      } else if (instanceType.isCompatibleWith(Character.class)) {
        return (T) Character.valueOf(new String(
            new byte[]{getNextRandom().byteValue()}, Charset.defaultCharset()).charAt(0));
      }
      return (T) this.getNextRandom();
    } catch (final Exception e) {
      throw new ObjectCreationException(instanceType, e);
    }
  }

  @Override
  public  T nextEmpty(final InstanceType instanceType, final FixtureContract fixture) {
    return next(instanceType, fixture);
  }

  @Override
  public void setOmittingAutoProperties(final boolean isOn) {

  }

  private long bytesToLong(final byte[] bytes) {
    final ByteBuffer buffer = ByteBuffer.allocate(8);
    buffer.put(bytes);
    buffer.flip();
    return buffer.getLong();
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy