seedgen 0.3.0

Zero-config database seed data generator with deterministic, constraint-safe fake data
Documentation
use rand::Rng;
use rand_chacha::ChaCha8Rng;

use super::{Generator, Value};

pub use super::text::UrlGenerator;

pub struct IPv4Generator;
impl Generator for IPv4Generator {
    fn generate(&self, rng: &mut ChaCha8Rng) -> Value {
        let a: u8 = rng.gen_range(1..=254);
        let b: u8 = rng.gen_range(0..=255);
        let c: u8 = rng.gen_range(0..=255);
        let d: u8 = rng.gen_range(1..=254);
        Value::String(format!("{a}.{b}.{c}.{d}"))
    }
    fn name(&self) -> &str {
        "ipv4"
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand::SeedableRng;

    fn rng(seed: u64) -> ChaCha8Rng {
        ChaCha8Rng::seed_from_u64(seed)
    }

    #[test]
    fn test_ipv4_is_deterministic() {
        let g = IPv4Generator;
        let mut a = rng(5);
        let mut b = rng(5);
        for _ in 0..20 {
            assert_eq!(g.generate(&mut a), g.generate(&mut b));
        }
    }

    #[test]
    fn test_ipv4_format_and_bounds() {
        let g = IPv4Generator;
        let mut r = rng(1);
        for _ in 0..50 {
            let s = match g.generate(&mut r) {
                Value::String(s) => s,
                other => panic!("expected String, got {other:?}"),
            };
            let parts: Vec<&str> = s.split('.').collect();
            assert_eq!(parts.len(), 4, "got {s:?}");
            let nums: Vec<u32> = parts.iter().map(|p| p.parse::<u32>().unwrap()).collect();
            assert!(nums[0] >= 1 && nums[0] <= 254, "first octet: {s}");
            assert!(nums[1] <= 255, "got {s}");
            assert!(nums[2] <= 255, "got {s}");
            assert!(nums[3] >= 1 && nums[3] <= 254, "last octet: {s}");
        }
    }

    #[test]
    fn test_url_reexport_still_works() {
        let g = UrlGenerator;
        let mut r = rng(1);
        match g.generate(&mut r) {
            Value::String(s) => assert!(s.starts_with("https://"), "got {s:?}"),
            other => panic!("expected String, got {other:?}"),
        }
    }
}