namespace StellaOps.TestKit.Deterministic;
///
/// Provides deterministic random number generation for testing.
/// Uses a fixed seed to ensure reproducible random sequences.
///
///
/// Usage:
///
/// var random = new DeterministicRandom(seed: 42);
/// var value1 = random.Next(); // Same value every time with seed 42
/// var value2 = random.NextDouble(); // Deterministic sequence
///
/// // For property-based testing with FsCheck
/// var gen = DeterministicRandom.CreateGen(seed: 42);
///
///
public sealed class DeterministicRandom
{
private readonly System.Random _random;
private readonly int _seed;
///
/// Creates a new deterministic random number generator with the specified seed.
///
/// The seed value. Same seed always produces same sequence.
public DeterministicRandom(int seed)
{
_seed = seed;
_random = new System.Random(seed);
}
///
/// Gets the seed used for this random number generator.
///
public int Seed => _seed;
///
/// Returns a non-negative random integer.
///
public int Next() => _random.Next();
///
/// Returns a non-negative random integer less than the specified maximum.
///
public int Next(int maxValue) => _random.Next(maxValue);
///
/// Returns a random integer within the specified range.
///
public int Next(int minValue, int maxValue) => _random.Next(minValue, maxValue);
///
/// Returns a random floating-point number between 0.0 and 1.0.
///
public double NextDouble() => _random.NextDouble();
///
/// Fills the elements of the specified array with random bytes.
///
public void NextBytes(byte[] buffer) => _random.NextBytes(buffer);
///
/// Fills the elements of the specified span with random bytes.
///
public void NextBytes(Span buffer) => _random.NextBytes(buffer);
///
/// Creates a new deterministic Random instance with the specified seed.
/// Useful for integration with code that expects System.Random.
///
public static System.Random CreateRandom(int seed) => new(seed);
///
/// Generates a deterministic GUID based on the seed.
///
public Guid NextGuid()
{
var bytes = new byte[16];
_random.NextBytes(bytes);
return new Guid(bytes);
}
///
/// Generates a deterministic string of the specified length using alphanumeric characters.
///
public string NextString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var result = new char[length];
for (int i = 0; i < length; i++)
{
result[i] = chars[_random.Next(chars.Length)];
}
return new string(result);
}
///
/// Selects a random element from the specified array.
///
public T NextElement(T[] array)
{
if (array == null || array.Length == 0)
{
throw new ArgumentException("Array cannot be null or empty", nameof(array));
}
return array[_random.Next(array.Length)];
}
///
/// Shuffles an array in-place using the Fisher-Yates algorithm (deterministic).
///
public void Shuffle(T[] array)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
for (int i = array.Length - 1; i > 0; i--)
{
int j = _random.Next(i + 1);
(array[i], array[j]) = (array[j], array[i]);
}
}
}