regd_testing/rand.rs
1// Copyright 2025 Shingo OKAWA. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module contains a set of testing utilities of random value generators.
16
17use std::fs;
18
19use rand::Rng;
20use rand::distr::uniform::{SampleRange, SampleUniform};
21use rand::distr::{Alphanumeric, StandardUniform};
22use rand::prelude::Distribution;
23
24/// Generates a random value of type `T`.
25///
26/// This function uses the default random number generator to produce a value of type `T`.
27/// The type `T` must implement the `Distribution` trait for `StandardUniform`.
28///
29/// # Returns
30/// - A randomly generated value of type `T`.
31///
32/// # Examples
33/// ```
34/// use regd_testing;
35///
36/// let x: u32 = regd_testing::rand::generate();
37/// println!("Generated number: {}", x);
38/// ```
39///
40/// # Panics
41/// - This function may panic if `T` does not implement `Distribution` for `StandardUniform`.
42pub fn generate<T>() -> T
43where
44 StandardUniform: Distribution<T>,
45{
46 let mut rng = rand::rng();
47 rng.random::<T>()
48}
49
50/// Generates a random value of type `T` within the specified range.
51///
52/// This function returns a randomly selected value of type `T` from the provided range.
53/// The type `T` must implement `SampleUniform`, and the range must implement `SampleRange<T>`.
54///
55/// # Parameters
56/// - `range`: The range from which to generate a random value.
57///
58/// # Returns
59/// - A randomly generated value of type `T` within the specified range.
60///
61/// # Examples
62/// ```
63/// use regd_testing;
64///
65/// let x: i32 = regd_testing::rand::generate_range(10..20);
66/// println!("Generated value: {}", x);
67///
68/// let y: f64 = regd_testing::rand::generate_range(1.0..5.0);
69/// println!("Generated float value: {}", y);
70/// ```
71///
72/// # Panics
73/// - This function will panic if the provided range is empty.
74pub fn generate_range<T, R>(range: R) -> T
75where
76 T: SampleUniform,
77 R: SampleRange<T>,
78{
79 assert!(!range.is_empty(), "cannot sample empty range");
80 let mut rng = rand::rng();
81 rng.random_range(range)
82}
83
84/// Generates a vector of random bytes of the specified length.
85///
86/// This function returns a `Vec<u8>` filled with random byte values (`u8`)
87/// generated using the thread-local random number generator.
88///
89/// # Parameters
90/// - `length`: The number of random bytes to generate.
91///
92/// # Returns
93/// - A `Vec<u8>` containing `length` random bytes.
94///
95/// # Examples
96/// ```
97/// use regd_testing;
98///
99/// let x = regd_testing::rand::generate_bytes(16);
100/// assert_eq!(x.len(), 16);
101/// println!("Random bytes: {:?}", x);
102/// ```
103pub fn generate_bytes(length: usize) -> Vec<u8> {
104 let mut rng = rand::rng();
105 (0..length).map(|_| rng.random::<u8>()).collect()
106}
107
108/// Generates a random alphanumeric string of the specified length.
109///
110/// This function creates a string consisting of randomly selected characters from the
111/// alphanumeric set (`A-Z`, `a-z`, `0-9`) using the thread-local random number generator.
112///
113/// # Parameters
114/// - `length`: The length of the generated string.
115///
116/// # Returns
117/// - A `String` containing `length` randomly chosen alphanumeric characters.
118///
119/// # Examples
120/// ```
121/// use regd_testing;
122///
123/// let x = regd_testing::rand::generate_alphanumeric(12);
124/// println!("Generated token: {}", x);
125/// assert_eq!(x.len(), 12);
126/// ```
127pub fn generate_alphanumeric(length: usize) -> String {
128 let rng = rand::rng();
129 rng.sample_iter(&Alphanumeric)
130 .take(length)
131 .map(char::from)
132 .collect()
133}
134
135/// Generates a random alphanumeric filename that does not exist in the current directory.
136///
137/// This function creates a random alphanumeric string of the specified length,
138/// checks whether a file with that name already exists in the current working directory,
139/// and returns it only if the name is **not** already used. This ensures that the generated
140/// filename can safely be used for temporary files or testing without clashing with existing files.
141///
142/// # Parameters
143/// - `length`: The length of the generated filename. Must be greater than 0.
144///
145/// # Returns
146/// - A `String` representing a randomly generated, non-existent filename.
147///
148/// # Examples
149/// ```
150/// use regd_testing;
151///
152/// let x = regd_testing::rand::generate_badfile(12);
153/// println!("Generated unique filename: {}", x);
154/// assert!(std::fs::metadata(&x).is_err()); // Confirm file does not exist
155/// ```
156///
157/// # Panics
158/// - This function will panic if `length == 0`.
159///
160/// # Notes
161/// - The function uses a loop and may retry multiple times if name collisions occur,
162/// although with a reasonable `length` (e.g., ≥8), collisions are very unlikely.
163/// - The check is limited to the **current working directory**.
164pub fn generate_badfile(length: usize) -> String {
165 assert!(length > 0, "cannot sample empty file name");
166 loop {
167 let rng = rand::rng();
168 let filename: String = rng
169 .sample_iter(&Alphanumeric)
170 .take(length)
171 .map(char::from)
172 .collect();
173 if fs::metadata(&filename).is_err() {
174 return filename;
175 }
176 }
177}