Skip to main content

ferro_rs/testing/
factory.rs

1//! Database factories for generating fake test data
2//!
3//! Provides Rails/Laravel-like model factories with database persistence.
4//!
5//! # Basic Usage
6//!
7//! ```rust,ignore
8//! use ferro_rs::testing::{Factory, Fake};
9//!
10//! // Define a factory for your model
11//! impl Factory for User {
12//!     fn definition() -> Self {
13//!         User {
14//!             id: 0, // Will be set by database
15//!             name: Fake::name(),
16//!             email: Fake::email(),
17//!             created_at: Fake::datetime(),
18//!         }
19//!     }
20//! }
21//!
22//! // Make without persisting
23//! let user = User::factory().make();
24//!
25//! // Create with database persistence
26//! let user = User::factory().create().await?;
27//!
28//! // Create multiple
29//! let users = User::factory().count(5).create_many().await?;
30//! ```
31//!
32//! # Factory Traits (Named States)
33//!
34//! ```rust,ignore
35//! impl Factory for User {
36//!     fn definition() -> Self { /* ... */ }
37//!
38//!     fn traits() -> FactoryTraits<Self> {
39//!         FactoryTraits::new()
40//!             .define("admin", |u| u.role = "admin".into())
41//!             .define("verified", |u| u.verified_at = Some(Fake::datetime()))
42//!             .define("unverified", |u| u.verified_at = None)
43//!     }
44//! }
45//!
46//! // Use traits
47//! let admin = User::factory().trait_("admin").create().await?;
48//! let verified_admin = User::factory()
49//!     .trait_("admin")
50//!     .trait_("verified")
51//!     .create()
52//!     .await?;
53//! ```
54//!
55//! # Callbacks
56//!
57//! ```rust,ignore
58//! let user = User::factory()
59//!     .after_make(|u| println!("Made user: {}", u.name))
60//!     .after_create(|u| {
61//!         // Create related records
62//!         Profile::factory()
63//!             .state(|p| p.user_id = u.id)
64//!             .create()
65//!             .await
66//!     })
67//!     .create()
68//!     .await?;
69//! ```
70//!
71//! # Associations
72//!
73//! Use `set()` for belongs_to relationships:
74//!
75//! ```rust,ignore
76//! // Create a user first, then a post belonging to that user
77//! let user = User::factory().create().await?;
78//!
79//! let post = Post::factory()
80//!     .set(user.id, |p, user_id| p.user_id = user_id)
81//!     .create()
82//!     .await?;
83//!
84//! // Create multiple posts for the same user (has_many)
85//! let posts = Post::factory()
86//!     .count(5)
87//!     .set(user.id, |p, user_id| p.user_id = user_id)
88//!     .create_many()
89//!     .await?;
90//! ```
91//!
92//! Use `after_create` for creating child records:
93//!
94//! ```rust,ignore
95//! let user = User::factory()
96//!     .after_create(|user| async move {
97//!         // Create related profile
98//!         Profile::factory()
99//!             .set(user.id, |p, id| p.user_id = id)
100//!             .create()
101//!             .await?;
102//!         Ok(())
103//!     })
104//!     .create()
105//!     .await?;
106//! ```
107
108use crate::database::DB;
109use crate::error::FrameworkError;
110use async_trait::async_trait;
111use rand::Rng;
112use sea_orm::{ActiveModelBehavior, ActiveModelTrait, EntityTrait, IntoActiveModel};
113use std::collections::HashMap;
114use std::future::Future;
115use std::pin::Pin;
116use std::sync::Arc;
117
118/// Trait for models that can be created via factories
119pub trait Factory: Sized + Clone + Send + 'static {
120    /// Define the default state of the model
121    fn definition() -> Self;
122
123    /// Define named traits (states) for this factory
124    fn traits() -> FactoryTraits<Self> {
125        FactoryTraits::new()
126    }
127
128    /// Create a factory builder for this model
129    fn factory() -> FactoryBuilder<Self> {
130        FactoryBuilder::new()
131    }
132}
133
134/// Trait for models that can be persisted to database via factories
135///
136/// Implement this trait for SeaORM entities to enable `create()` and `create_many()`.
137///
138/// # Example
139///
140/// ```rust,ignore
141/// use ferro_rs::testing::{Factory, DatabaseFactory, Fake};
142/// use sea_orm::ActiveValue::Set;
143///
144/// impl Factory for user::Model {
145///     fn definition() -> Self {
146///         Self {
147///             id: 0,
148///             name: Fake::name(),
149///             email: Fake::email(),
150///             created_at: chrono::Utc::now().naive_utc(),
151///         }
152///     }
153/// }
154///
155/// impl DatabaseFactory for user::Model {
156///     type Entity = user::Entity;
157///     type ActiveModel = user::ActiveModel;
158///
159///     fn to_active_model(model: Self) -> Self::ActiveModel {
160///         user::ActiveModel {
161///             name: Set(model.name),
162///             email: Set(model.email),
163///             ..Default::default()
164///         }
165///     }
166/// }
167/// ```
168/// Trait for models that can be persisted to database via factories
169///
170/// Implement this trait for SeaORM entities to enable `create()` and `create_many()`.
171#[async_trait]
172pub trait DatabaseFactory: Factory + IntoActiveModel<Self::ActiveModel> {
173    /// The SeaORM entity type
174    type Entity: EntityTrait<Model = Self>;
175    /// The SeaORM active model type
176    type ActiveModel: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send;
177
178    /// Insert a model into the database
179    async fn insert(model: Self) -> Result<Self, FrameworkError>
180    where
181        Self: Sized,
182    {
183        let db = DB::get()?;
184        let active_model: Self::ActiveModel = model.into_active_model();
185        let result = active_model.insert(db.inner()).await.map_err(|e| {
186            FrameworkError::internal(format!("Failed to insert factory model: {e}"))
187        })?;
188        Ok(result)
189    }
190}
191
192/// Type alias for state modifier function
193type StateModifier<T> = Arc<dyn Fn(&mut T) + Send + Sync>;
194
195/// Type alias for after-make callback
196type AfterMakeCallback<T> = Arc<dyn Fn(&T) + Send + Sync>;
197
198/// Collection of named traits (states) for a factory
199pub struct FactoryTraits<T> {
200    traits: HashMap<&'static str, StateModifier<T>>,
201}
202
203impl<T> FactoryTraits<T> {
204    /// Create a new empty traits collection
205    pub fn new() -> Self {
206        Self {
207            traits: HashMap::new(),
208        }
209    }
210
211    /// Define a named trait
212    pub fn define<F>(mut self, name: &'static str, f: F) -> Self
213    where
214        F: Fn(&mut T) + Send + Sync + 'static,
215    {
216        self.traits.insert(name, Arc::new(f));
217        self
218    }
219
220    /// Get a trait by name
221    pub fn get(&self, name: &str) -> Option<StateModifier<T>> {
222        self.traits.get(name).cloned()
223    }
224}
225
226impl<T> Default for FactoryTraits<T> {
227    fn default() -> Self {
228        Self::new()
229    }
230}
231
232/// Type alias for async after_create callbacks
233type AfterCreateCallback<T> =
234    Box<dyn Fn(T) -> Pin<Box<dyn Future<Output = Result<(), FrameworkError>> + Send>> + Send>;
235
236/// Builder for creating model instances with customizations
237pub struct FactoryBuilder<T: Factory> {
238    count: usize,
239    states: Vec<StateModifier<T>>,
240    trait_names: Vec<&'static str>,
241    after_make_callbacks: Vec<AfterMakeCallback<T>>,
242    after_create_callbacks: Vec<AfterCreateCallback<T>>,
243}
244
245impl<T: Factory> FactoryBuilder<T> {
246    /// Create a new factory builder
247    pub fn new() -> Self {
248        Self {
249            count: 1,
250            states: Vec::new(),
251            trait_names: Vec::new(),
252            after_make_callbacks: Vec::new(),
253            after_create_callbacks: Vec::new(),
254        }
255    }
256
257    /// Set the number of models to create
258    pub fn count(mut self, count: usize) -> Self {
259        self.count = count;
260        self
261    }
262
263    /// Apply a state transformation to the model
264    pub fn state<F>(mut self, f: F) -> Self
265    where
266        F: Fn(&mut T) + Send + Sync + 'static,
267    {
268        self.states.push(Arc::new(f));
269        self
270    }
271
272    /// Set a field value using a setter function
273    ///
274    /// This is useful for setting foreign keys when creating associated models.
275    /// The value is cloned for each model when creating multiple instances.
276    ///
277    /// # Example
278    ///
279    /// ```rust,ignore
280    /// // Create a user first, then create posts belonging to that user
281    /// let user = User::factory().create().await?;
282    ///
283    /// let post = Post::factory()
284    ///     .set(user.id, |p, user_id| p.user_id = user_id)
285    ///     .create()
286    ///     .await?;
287    ///
288    /// // Create multiple posts for the same user
289    /// let posts = Post::factory()
290    ///     .count(5)
291    ///     .set(user.id, |p, user_id| p.user_id = user_id)
292    ///     .create_many()
293    ///     .await?;
294    /// ```
295    pub fn set<V, F>(mut self, value: V, setter: F) -> Self
296    where
297        V: Clone + Send + Sync + 'static,
298        F: Fn(&mut T, V) + Send + Sync + 'static,
299    {
300        self.states
301            .push(Arc::new(move |m| setter(m, value.clone())));
302        self
303    }
304
305    /// Apply a named trait (state) defined in the Factory
306    ///
307    /// # Example
308    ///
309    /// ```rust,ignore
310    /// let admin = User::factory()
311    ///     .trait_("admin")
312    ///     .trait_("verified")
313    ///     .create()
314    ///     .await?;
315    /// ```
316    pub fn trait_(mut self, name: &'static str) -> Self {
317        self.trait_names.push(name);
318        self
319    }
320
321    /// Add a callback to run after making (but before persisting)
322    ///
323    /// # Example
324    ///
325    /// ```rust,ignore
326    /// let user = User::factory()
327    ///     .after_make(|u| println!("Made user: {}", u.name))
328    ///     .create()
329    ///     .await?;
330    /// ```
331    pub fn after_make<F>(mut self, f: F) -> Self
332    where
333        F: Fn(&T) + Send + Sync + 'static,
334    {
335        self.after_make_callbacks.push(Arc::new(f));
336        self
337    }
338
339    /// Add an async callback to run after creating (persisting to database)
340    ///
341    /// # Example
342    ///
343    /// ```rust,ignore
344    /// let user = User::factory()
345    ///     .after_create(|u| async move {
346    ///         // Create related records
347    ///         Profile::factory()
348    ///             .state(|p| p.user_id = u.id)
349    ///             .create()
350    ///             .await?;
351    ///         Ok(())
352    ///     })
353    ///     .create()
354    ///     .await?;
355    /// ```
356    pub fn after_create<F, Fut>(mut self, f: F) -> Self
357    where
358        F: Fn(T) -> Fut + Send + 'static,
359        Fut: Future<Output = Result<(), FrameworkError>> + Send + 'static,
360        T: Clone,
361    {
362        self.after_create_callbacks
363            .push(Box::new(move |model: T| Box::pin(f(model))));
364        self
365    }
366
367    /// Build a single model instance without persisting
368    pub fn make(self) -> T {
369        let mut instance = T::definition();
370
371        // Apply named traits
372        let traits = T::traits();
373        for trait_name in &self.trait_names {
374            if let Some(trait_fn) = traits.get(trait_name) {
375                trait_fn(&mut instance);
376            }
377        }
378
379        // Apply inline states
380        for state in &self.states {
381            state(&mut instance);
382        }
383
384        // Run after_make callbacks
385        for callback in &self.after_make_callbacks {
386            callback(&instance);
387        }
388
389        instance
390    }
391
392    /// Build multiple model instances without persisting
393    pub fn make_many(self) -> Vec<T> {
394        let count = self.count;
395        let traits = T::traits();
396
397        (0..count)
398            .map(|_| {
399                let mut instance = T::definition();
400
401                // Apply named traits
402                for trait_name in &self.trait_names {
403                    if let Some(trait_fn) = traits.get(trait_name) {
404                        trait_fn(&mut instance);
405                    }
406                }
407
408                // Apply inline states
409                for state in &self.states {
410                    state(&mut instance);
411                }
412
413                // Run after_make callbacks
414                for callback in &self.after_make_callbacks {
415                    callback(&instance);
416                }
417
418                instance
419            })
420            .collect()
421    }
422}
423
424impl<T: Factory> Default for FactoryBuilder<T> {
425    fn default() -> Self {
426        Self::new()
427    }
428}
429
430// Database persistence methods (only available when T: DatabaseFactory)
431impl<T: DatabaseFactory> FactoryBuilder<T> {
432    /// Create a single model instance and persist to database
433    ///
434    /// # Example
435    ///
436    /// ```rust,ignore
437    /// let user = User::factory()
438    ///     .state(|u| u.name = "John".into())
439    ///     .create()
440    ///     .await?;
441    /// ```
442    pub async fn create(self) -> Result<T, FrameworkError> {
443        let mut instance = T::definition();
444        let traits = T::traits();
445
446        // Apply named traits
447        for trait_name in &self.trait_names {
448            if let Some(trait_fn) = traits.get(trait_name) {
449                trait_fn(&mut instance);
450            }
451        }
452
453        // Apply inline states
454        for state in &self.states {
455            state(&mut instance);
456        }
457
458        // Run after_make callbacks
459        for callback in &self.after_make_callbacks {
460            callback(&instance);
461        }
462
463        // Insert into database
464        let created = T::insert(instance).await?;
465
466        // Run after_create callbacks
467        for callback in &self.after_create_callbacks {
468            callback(created.clone()).await?;
469        }
470
471        Ok(created)
472    }
473
474    /// Create multiple model instances and persist to database
475    ///
476    /// # Example
477    ///
478    /// ```rust,ignore
479    /// let users = User::factory()
480    ///     .count(5)
481    ///     .create_many()
482    ///     .await?;
483    /// ```
484    pub async fn create_many(self) -> Result<Vec<T>, FrameworkError> {
485        let count = self.count;
486        let after_create_callbacks = self.after_create_callbacks;
487        let traits = T::traits();
488
489        let mut results = Vec::with_capacity(count);
490
491        for _ in 0..count {
492            let mut instance = T::definition();
493
494            // Apply named traits
495            for trait_name in &self.trait_names {
496                if let Some(trait_fn) = traits.get(trait_name) {
497                    trait_fn(&mut instance);
498                }
499            }
500
501            // Apply inline states
502            for state in &self.states {
503                state(&mut instance);
504            }
505
506            // Run after_make callbacks
507            for callback in &self.after_make_callbacks {
508                callback(&instance);
509            }
510
511            // Insert into database
512            let created = T::insert(instance).await?;
513
514            // Run after_create callbacks
515            for callback in &after_create_callbacks {
516                callback(created.clone()).await?;
517            }
518
519            results.push(created);
520        }
521
522        Ok(results)
523    }
524}
525
526/// Helper for generating fake data
527///
528/// Provides convenient methods for generating common types of fake data.
529///
530/// # Example
531///
532/// ```rust,ignore
533/// use ferro_rs::testing::Fake;
534///
535/// let name = Fake::name();
536/// let email = Fake::email();
537/// let sentence = Fake::sentence();
538/// ```
539pub struct Fake;
540
541impl Fake {
542    /// Generate a random first name
543    pub fn first_name() -> String {
544        let names = [
545            "James",
546            "Mary",
547            "John",
548            "Patricia",
549            "Robert",
550            "Jennifer",
551            "Michael",
552            "Linda",
553            "William",
554            "Elizabeth",
555            "David",
556            "Barbara",
557            "Richard",
558            "Susan",
559            "Joseph",
560            "Jessica",
561            "Thomas",
562            "Sarah",
563            "Charles",
564            "Karen",
565            "Emma",
566            "Olivia",
567            "Ava",
568            "Isabella",
569            "Sophia",
570            "Mia",
571            "Charlotte",
572            "Amelia",
573            "Harper",
574            "Evelyn",
575        ];
576        let mut rng = rand::thread_rng();
577        names[rng.gen_range(0..names.len())].to_string()
578    }
579
580    /// Generate a random last name
581    pub fn last_name() -> String {
582        let names = [
583            "Smith",
584            "Johnson",
585            "Williams",
586            "Brown",
587            "Jones",
588            "Garcia",
589            "Miller",
590            "Davis",
591            "Rodriguez",
592            "Martinez",
593            "Hernandez",
594            "Lopez",
595            "Gonzalez",
596            "Wilson",
597            "Anderson",
598            "Thomas",
599            "Taylor",
600            "Moore",
601            "Jackson",
602            "Martin",
603            "Lee",
604            "Perez",
605            "Thompson",
606            "White",
607            "Harris",
608            "Sanchez",
609            "Clark",
610            "Ramirez",
611            "Lewis",
612            "Robinson",
613        ];
614        let mut rng = rand::thread_rng();
615        names[rng.gen_range(0..names.len())].to_string()
616    }
617
618    /// Generate a random full name
619    pub fn name() -> String {
620        format!("{} {}", Self::first_name(), Self::last_name())
621    }
622
623    /// Generate a random email address
624    pub fn email() -> String {
625        let mut rng = rand::thread_rng();
626        let id: u32 = rng.gen_range(1000..9999);
627        let domains = ["example.com", "test.com", "mail.test", "fake.org"];
628        let domain = domains[rng.gen_range(0..domains.len())];
629        format!(
630            "{}.{}{}@{}",
631            Self::first_name().to_lowercase(),
632            Self::last_name().to_lowercase(),
633            id,
634            domain
635        )
636    }
637
638    /// Generate a safe email (always @example.com)
639    pub fn safe_email() -> String {
640        let mut rng = rand::thread_rng();
641        let id: u32 = rng.gen_range(1000..9999);
642        format!(
643            "{}.{}{}@example.com",
644            Self::first_name().to_lowercase(),
645            Self::last_name().to_lowercase(),
646            id
647        )
648    }
649
650    /// Generate a random username
651    pub fn username() -> String {
652        let mut rng = rand::thread_rng();
653        let id: u32 = rng.gen_range(100..999);
654        format!(
655            "{}{}{}",
656            Self::first_name().to_lowercase(),
657            Self::last_name().chars().next().unwrap_or('x'),
658            id
659        )
660    }
661
662    /// Generate a random password (for testing only)
663    pub fn password() -> String {
664        let mut rng = rand::thread_rng();
665        let chars: Vec<char> =
666            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%"
667                .chars()
668                .collect();
669        (0..16)
670            .map(|_| chars[rng.gen_range(0..chars.len())])
671            .collect()
672    }
673
674    /// Generate a random sentence
675    pub fn sentence() -> String {
676        let words = [
677            "the",
678            "quick",
679            "brown",
680            "fox",
681            "jumps",
682            "over",
683            "lazy",
684            "dog",
685            "lorem",
686            "ipsum",
687            "dolor",
688            "sit",
689            "amet",
690            "consectetur",
691            "adipiscing",
692            "elit",
693            "sed",
694            "do",
695            "eiusmod",
696            "tempor",
697            "incididunt",
698            "ut",
699            "labore",
700            "et",
701            "dolore",
702            "magna",
703            "aliqua",
704            "enim",
705            "ad",
706            "minim",
707            "veniam",
708        ];
709        let mut rng = rand::thread_rng();
710        let count = rng.gen_range(5..12);
711        let sentence: Vec<&str> = (0..count)
712            .map(|_| words[rng.gen_range(0..words.len())])
713            .collect();
714        let mut s = sentence.join(" ");
715        if let Some(c) = s.get_mut(0..1) {
716            c.make_ascii_uppercase();
717        }
718        s.push('.');
719        s
720    }
721
722    /// Generate a random paragraph
723    pub fn paragraph() -> String {
724        let mut rng = rand::thread_rng();
725        let count = rng.gen_range(3..6);
726        (0..count)
727            .map(|_| Self::sentence())
728            .collect::<Vec<_>>()
729            .join(" ")
730    }
731
732    /// Generate random text of approximately the given length
733    pub fn text(approx_length: usize) -> String {
734        let mut result = String::new();
735        while result.len() < approx_length {
736            if !result.is_empty() {
737                result.push(' ');
738            }
739            result.push_str(&Self::paragraph());
740        }
741        result.truncate(approx_length);
742        result
743    }
744
745    /// Generate a random integer in a range
746    pub fn number(min: i64, max: i64) -> i64 {
747        let mut rng = rand::thread_rng();
748        rng.gen_range(min..=max)
749    }
750
751    /// Generate a random float in a range
752    pub fn float(min: f64, max: f64) -> f64 {
753        let mut rng = rand::thread_rng();
754        rng.gen_range(min..=max)
755    }
756
757    /// Generate a random boolean
758    pub fn boolean() -> bool {
759        let mut rng = rand::thread_rng();
760        rng.gen_bool(0.5)
761    }
762
763    /// Generate a random boolean with given probability of true
764    pub fn boolean_with_probability(probability: f64) -> bool {
765        let mut rng = rand::thread_rng();
766        rng.gen_bool(probability.clamp(0.0, 1.0))
767    }
768
769    /// Generate a random UUID v4
770    pub fn uuid() -> String {
771        let mut rng = rand::thread_rng();
772        let mut bytes: [u8; 16] = rng.gen();
773
774        // Set version to 4 (bits 4-7 of byte 6)
775        bytes[6] = (bytes[6] & 0x0f) | 0x40;
776        // Set variant to 10xx (bits 6-7 of byte 8)
777        bytes[8] = (bytes[8] & 0x3f) | 0x80;
778
779        format!(
780            "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
781            bytes[0], bytes[1], bytes[2], bytes[3],
782            bytes[4], bytes[5],
783            bytes[6], bytes[7],
784            bytes[8], bytes[9],
785            bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
786        )
787    }
788
789    /// Generate a random phone number
790    pub fn phone() -> String {
791        let mut rng = rand::thread_rng();
792        format!(
793            "+1-{:03}-{:03}-{:04}",
794            rng.gen_range(200..999),
795            rng.gen_range(200..999),
796            rng.gen_range(1000..9999)
797        )
798    }
799
800    /// Generate a random street address
801    pub fn address() -> String {
802        let mut rng = rand::thread_rng();
803        let streets = [
804            "Main St",
805            "Oak Ave",
806            "Maple Dr",
807            "Cedar Ln",
808            "Pine Rd",
809            "Elm St",
810            "Washington Blvd",
811            "Park Ave",
812            "Lake Dr",
813            "Hill Rd",
814        ];
815        format!(
816            "{} {}",
817            rng.gen_range(100..9999),
818            streets[rng.gen_range(0..streets.len())]
819        )
820    }
821
822    /// Generate a random city name
823    pub fn city() -> String {
824        let cities = [
825            "New York",
826            "Los Angeles",
827            "Chicago",
828            "Houston",
829            "Phoenix",
830            "Philadelphia",
831            "San Antonio",
832            "San Diego",
833            "Dallas",
834            "Austin",
835            "San Jose",
836            "Seattle",
837            "Denver",
838            "Boston",
839            "Portland",
840        ];
841        let mut rng = rand::thread_rng();
842        cities[rng.gen_range(0..cities.len())].to_string()
843    }
844
845    /// Generate a random US state
846    pub fn state() -> String {
847        let states = [
848            "Alabama",
849            "Alaska",
850            "Arizona",
851            "Arkansas",
852            "California",
853            "Colorado",
854            "Connecticut",
855            "Delaware",
856            "Florida",
857            "Georgia",
858            "Hawaii",
859            "Idaho",
860            "Illinois",
861            "Indiana",
862            "Iowa",
863        ];
864        let mut rng = rand::thread_rng();
865        states[rng.gen_range(0..states.len())].to_string()
866    }
867
868    /// Generate a random US zip code
869    pub fn zip_code() -> String {
870        let mut rng = rand::thread_rng();
871        format!("{:05}", rng.gen_range(10000..99999))
872    }
873
874    /// Generate a random country
875    pub fn country() -> String {
876        let countries = [
877            "United States",
878            "United Kingdom",
879            "Canada",
880            "Australia",
881            "Germany",
882            "France",
883            "Japan",
884            "Brazil",
885            "India",
886            "Mexico",
887        ];
888        let mut rng = rand::thread_rng();
889        countries[rng.gen_range(0..countries.len())].to_string()
890    }
891
892    /// Generate a random company name
893    pub fn company() -> String {
894        let prefixes = ["Tech", "Global", "United", "Advanced", "Premier", "Elite"];
895        let suffixes = ["Solutions", "Systems", "Industries", "Corp", "Inc", "LLC"];
896        let mut rng = rand::thread_rng();
897        format!(
898            "{} {} {}",
899            prefixes[rng.gen_range(0..prefixes.len())],
900            Self::last_name(),
901            suffixes[rng.gen_range(0..suffixes.len())]
902        )
903    }
904
905    /// Generate a random URL
906    pub fn url() -> String {
907        let mut rng = rand::thread_rng();
908        let tlds = ["com", "org", "net", "io", "co"];
909        format!(
910            "https://www.{}.{}",
911            Self::last_name().to_lowercase(),
912            tlds[rng.gen_range(0..tlds.len())]
913        )
914    }
915
916    /// Generate a random image URL (placeholder)
917    pub fn image_url(width: u32, height: u32) -> String {
918        format!("https://via.placeholder.com/{width}x{height}")
919    }
920
921    /// Generate a random hex color
922    pub fn hex_color() -> String {
923        let mut rng = rand::thread_rng();
924        format!(
925            "#{:02x}{:02x}{:02x}",
926            rng.gen_range(0..=255),
927            rng.gen_range(0..=255),
928            rng.gen_range(0..=255)
929        )
930    }
931
932    /// Generate a random IPv4 address
933    pub fn ipv4() -> String {
934        let mut rng = rand::thread_rng();
935        format!(
936            "{}.{}.{}.{}",
937            rng.gen_range(1..255),
938            rng.gen_range(0..255),
939            rng.gen_range(0..255),
940            rng.gen_range(1..255)
941        )
942    }
943
944    /// Generate a random MAC address
945    pub fn mac_address() -> String {
946        let mut rng = rand::thread_rng();
947        format!(
948            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
949            rng.gen_range(0..=255),
950            rng.gen_range(0..=255),
951            rng.gen_range(0..=255),
952            rng.gen_range(0..=255),
953            rng.gen_range(0..=255),
954            rng.gen_range(0..=255)
955        )
956    }
957
958    /// Generate a random date in YYYY-MM-DD format
959    pub fn date() -> String {
960        let mut rng = rand::thread_rng();
961        format!(
962            "{:04}-{:02}-{:02}",
963            rng.gen_range(2000..2025),
964            rng.gen_range(1..=12),
965            rng.gen_range(1..=28)
966        )
967    }
968
969    /// Generate a random datetime in ISO 8601 format
970    pub fn datetime() -> String {
971        let mut rng = rand::thread_rng();
972        format!(
973            "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z",
974            rng.gen_range(2000..2025),
975            rng.gen_range(1..=12),
976            rng.gen_range(1..=28),
977            rng.gen_range(0..24),
978            rng.gen_range(0..60),
979            rng.gen_range(0..60)
980        )
981    }
982
983    /// Generate a random future date
984    pub fn future_date() -> String {
985        let mut rng = rand::thread_rng();
986        format!(
987            "{:04}-{:02}-{:02}",
988            rng.gen_range(2025..2030),
989            rng.gen_range(1..=12),
990            rng.gen_range(1..=28)
991        )
992    }
993
994    /// Generate a random past date
995    pub fn past_date() -> String {
996        let mut rng = rand::thread_rng();
997        format!(
998            "{:04}-{:02}-{:02}",
999            rng.gen_range(2010..2024),
1000            rng.gen_range(1..=12),
1001            rng.gen_range(1..=28)
1002        )
1003    }
1004
1005    /// Generate a random slug from words
1006    pub fn slug() -> String {
1007        let words = ["hello", "world", "test", "example", "demo", "sample"];
1008        let mut rng = rand::thread_rng();
1009        let count = rng.gen_range(2..4);
1010        (0..count)
1011            .map(|_| words[rng.gen_range(0..words.len())])
1012            .collect::<Vec<_>>()
1013            .join("-")
1014    }
1015
1016    /// Pick a random element from a slice
1017    pub fn one_of<T: Clone>(items: &[T]) -> T {
1018        let mut rng = rand::thread_rng();
1019        items[rng.gen_range(0..items.len())].clone()
1020    }
1021
1022    /// Pick n random elements from a slice
1023    pub fn many_of<T: Clone>(items: &[T], count: usize) -> Vec<T> {
1024        let mut rng = rand::thread_rng();
1025        let count = count.min(items.len());
1026        let mut indices: Vec<usize> = (0..items.len()).collect();
1027
1028        // Fisher-Yates shuffle for first n elements
1029        for i in 0..count {
1030            let j = rng.gen_range(i..items.len());
1031            indices.swap(i, j);
1032        }
1033
1034        indices[..count].iter().map(|&i| items[i].clone()).collect()
1035    }
1036
1037    /// Generate a random credit card number (for testing only, not valid)
1038    pub fn credit_card() -> String {
1039        let mut rng = rand::thread_rng();
1040        format!(
1041            "4{:03}-{:04}-{:04}-{:04}",
1042            rng.gen_range(0..1000),
1043            rng.gen_range(0..10000),
1044            rng.gen_range(0..10000),
1045            rng.gen_range(0..10000)
1046        )
1047    }
1048
1049    /// Generate random bytes
1050    pub fn bytes(length: usize) -> Vec<u8> {
1051        let mut rng = rand::thread_rng();
1052        (0..length).map(|_| rng.gen()).collect()
1053    }
1054
1055    /// Generate a random hex string
1056    pub fn hex(length: usize) -> String {
1057        Self::bytes(length / 2 + 1)
1058            .iter()
1059            .map(|b| format!("{b:02x}"))
1060            .collect::<String>()
1061            .chars()
1062            .take(length)
1063            .collect()
1064    }
1065}
1066
1067/// Convenience function to create a sequence of unique items
1068pub struct Sequence {
1069    current: usize,
1070}
1071
1072impl Sequence {
1073    /// Create a new sequence starting at 1
1074    pub fn new() -> Self {
1075        Self { current: 0 }
1076    }
1077
1078    /// Create a sequence starting at a specific value
1079    pub fn starting_at(value: usize) -> Self {
1080        Self {
1081            current: value.saturating_sub(1),
1082        }
1083    }
1084
1085    /// Get the next value in the sequence
1086    #[allow(clippy::should_implement_trait)]
1087    pub fn next(&mut self) -> usize {
1088        self.current += 1;
1089        self.current
1090    }
1091
1092    /// Get the next value as a string with prefix
1093    pub fn next_with_prefix(&mut self, prefix: &str) -> String {
1094        format!("{}{}", prefix, self.next())
1095    }
1096}
1097
1098impl Default for Sequence {
1099    fn default() -> Self {
1100        Self::new()
1101    }
1102}
1103
1104#[cfg(test)]
1105mod tests {
1106    use super::*;
1107
1108    #[test]
1109    fn test_fake_name() {
1110        let name = Fake::name();
1111        assert!(!name.is_empty());
1112        assert!(name.contains(' '));
1113    }
1114
1115    #[test]
1116    fn test_fake_email() {
1117        let email = Fake::email();
1118        assert!(email.contains('@'));
1119        assert!(email.contains('.'));
1120    }
1121
1122    #[test]
1123    fn test_fake_uuid() {
1124        let uuid = Fake::uuid();
1125        assert_eq!(uuid.len(), 36);
1126        assert!(uuid.contains('-'));
1127    }
1128
1129    #[test]
1130    fn test_fake_sentence() {
1131        let sentence = Fake::sentence();
1132        assert!(!sentence.is_empty());
1133        assert!(sentence.ends_with('.'));
1134        // First character should be uppercase
1135        assert!(sentence.chars().next().unwrap().is_uppercase());
1136    }
1137
1138    #[test]
1139    fn test_fake_number() {
1140        let num = Fake::number(1, 10);
1141        assert!((1..=10).contains(&num));
1142    }
1143
1144    #[test]
1145    fn test_fake_one_of() {
1146        let options = vec!["a", "b", "c"];
1147        let choice = Fake::one_of(&options);
1148        assert!(options.contains(&choice));
1149    }
1150
1151    #[test]
1152    fn test_sequence() {
1153        let mut seq = Sequence::new();
1154        assert_eq!(seq.next(), 1);
1155        assert_eq!(seq.next(), 2);
1156        assert_eq!(seq.next(), 3);
1157    }
1158
1159    #[test]
1160    fn test_sequence_with_prefix() {
1161        let mut seq = Sequence::new();
1162        assert_eq!(seq.next_with_prefix("user_"), "user_1");
1163        assert_eq!(seq.next_with_prefix("user_"), "user_2");
1164    }
1165
1166    // Test factory pattern with a simple struct
1167    #[derive(Clone)]
1168    struct TestModel {
1169        id: i32,
1170        name: String,
1171        email: String,
1172        role: String,
1173        verified: bool,
1174    }
1175
1176    impl Factory for TestModel {
1177        fn definition() -> Self {
1178            Self {
1179                id: Fake::number(1, 1000) as i32,
1180                name: Fake::name(),
1181                email: Fake::email(),
1182                role: "user".to_string(),
1183                verified: false,
1184            }
1185        }
1186
1187        fn traits() -> FactoryTraits<Self> {
1188            FactoryTraits::new()
1189                .define("admin", |m: &mut Self| m.role = "admin".to_string())
1190                .define("verified", |m: &mut Self| m.verified = true)
1191        }
1192    }
1193
1194    #[test]
1195    fn test_factory_make() {
1196        let model = TestModel::factory().make();
1197        assert!(!model.name.is_empty());
1198        assert!(model.email.contains('@'));
1199    }
1200
1201    #[test]
1202    fn test_factory_with_state() {
1203        let model = TestModel::factory()
1204            .state(|m| m.name = "Custom Name".to_string())
1205            .make();
1206        assert_eq!(model.name, "Custom Name");
1207    }
1208
1209    #[test]
1210    fn test_factory_make_many() {
1211        let models = TestModel::factory().count(5).make_many();
1212        assert_eq!(models.len(), 5);
1213    }
1214
1215    #[test]
1216    fn test_factory_with_trait() {
1217        let admin = TestModel::factory().trait_("admin").make();
1218        assert_eq!(admin.role, "admin");
1219    }
1220
1221    #[test]
1222    fn test_factory_with_multiple_traits() {
1223        let verified_admin = TestModel::factory()
1224            .trait_("admin")
1225            .trait_("verified")
1226            .make();
1227        assert_eq!(verified_admin.role, "admin");
1228        assert!(verified_admin.verified);
1229    }
1230
1231    #[test]
1232    fn test_factory_trait_with_state_override() {
1233        let model = TestModel::factory()
1234            .trait_("admin")
1235            .state(|m| m.role = "superadmin".to_string())
1236            .make();
1237        // State should override trait
1238        assert_eq!(model.role, "superadmin");
1239    }
1240
1241    #[test]
1242    fn test_factory_after_make_callback() {
1243        use std::sync::atomic::{AtomicBool, Ordering};
1244        use std::sync::Arc;
1245
1246        let callback_ran = Arc::new(AtomicBool::new(false));
1247        let callback_ran_clone = callback_ran.clone();
1248
1249        let _model = TestModel::factory()
1250            .after_make(move |_| {
1251                callback_ran_clone.store(true, Ordering::SeqCst);
1252            })
1253            .make();
1254
1255        assert!(callback_ran.load(Ordering::SeqCst));
1256    }
1257
1258    #[test]
1259    fn test_factory_set_value() {
1260        // Test set() for foreign key style associations
1261        let parent_id = 42;
1262
1263        let model = TestModel::factory()
1264            .set(parent_id, |m, id| m.id = id)
1265            .make();
1266
1267        assert_eq!(model.id, 42);
1268    }
1269
1270    #[test]
1271    fn test_factory_set_multiple_values() {
1272        // Test multiple set() calls
1273        let model = TestModel::factory()
1274            .set(99, |m, id| m.id = id)
1275            .set("Manager".to_string(), |m, role| m.role = role)
1276            .make();
1277
1278        assert_eq!(model.id, 99);
1279        assert_eq!(model.role, "Manager");
1280    }
1281}