1use 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
118pub trait Factory: Sized + Clone + Send + 'static {
120 fn definition() -> Self;
122
123 fn traits() -> FactoryTraits<Self> {
125 FactoryTraits::new()
126 }
127
128 fn factory() -> FactoryBuilder<Self> {
130 FactoryBuilder::new()
131 }
132}
133
134#[async_trait]
172pub trait DatabaseFactory: Factory + IntoActiveModel<Self::ActiveModel> {
173 type Entity: EntityTrait<Model = Self>;
175 type ActiveModel: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send;
177
178 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
192type StateModifier<T> = Arc<dyn Fn(&mut T) + Send + Sync>;
194
195type AfterMakeCallback<T> = Arc<dyn Fn(&T) + Send + Sync>;
197
198pub struct FactoryTraits<T> {
200 traits: HashMap<&'static str, StateModifier<T>>,
201}
202
203impl<T> FactoryTraits<T> {
204 pub fn new() -> Self {
206 Self {
207 traits: HashMap::new(),
208 }
209 }
210
211 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 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
232type AfterCreateCallback<T> =
234 Box<dyn Fn(T) -> Pin<Box<dyn Future<Output = Result<(), FrameworkError>> + Send>> + Send>;
235
236pub 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 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 pub fn count(mut self, count: usize) -> Self {
259 self.count = count;
260 self
261 }
262
263 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 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 pub fn trait_(mut self, name: &'static str) -> Self {
317 self.trait_names.push(name);
318 self
319 }
320
321 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 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 pub fn make(self) -> T {
369 let mut instance = T::definition();
370
371 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 for state in &self.states {
381 state(&mut instance);
382 }
383
384 for callback in &self.after_make_callbacks {
386 callback(&instance);
387 }
388
389 instance
390 }
391
392 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 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 for state in &self.states {
410 state(&mut instance);
411 }
412
413 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
430impl<T: DatabaseFactory> FactoryBuilder<T> {
432 pub async fn create(self) -> Result<T, FrameworkError> {
443 let mut instance = T::definition();
444 let traits = T::traits();
445
446 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 for state in &self.states {
455 state(&mut instance);
456 }
457
458 for callback in &self.after_make_callbacks {
460 callback(&instance);
461 }
462
463 let created = T::insert(instance).await?;
465
466 for callback in &self.after_create_callbacks {
468 callback(created.clone()).await?;
469 }
470
471 Ok(created)
472 }
473
474 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 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 for state in &self.states {
503 state(&mut instance);
504 }
505
506 for callback in &self.after_make_callbacks {
508 callback(&instance);
509 }
510
511 let created = T::insert(instance).await?;
513
514 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
526pub struct Fake;
540
541impl Fake {
542 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 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 pub fn name() -> String {
620 format!("{} {}", Self::first_name(), Self::last_name())
621 }
622
623 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 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 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 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 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 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 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 pub fn number(min: i64, max: i64) -> i64 {
747 let mut rng = rand::thread_rng();
748 rng.gen_range(min..=max)
749 }
750
751 pub fn float(min: f64, max: f64) -> f64 {
753 let mut rng = rand::thread_rng();
754 rng.gen_range(min..=max)
755 }
756
757 pub fn boolean() -> bool {
759 let mut rng = rand::thread_rng();
760 rng.gen_bool(0.5)
761 }
762
763 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 pub fn uuid() -> String {
771 let mut rng = rand::thread_rng();
772 let mut bytes: [u8; 16] = rng.gen();
773
774 bytes[6] = (bytes[6] & 0x0f) | 0x40;
776 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 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 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 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 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 pub fn zip_code() -> String {
870 let mut rng = rand::thread_rng();
871 format!("{:05}", rng.gen_range(10000..99999))
872 }
873
874 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 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 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 pub fn image_url(width: u32, height: u32) -> String {
918 format!("https://via.placeholder.com/{width}x{height}")
919 }
920
921 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 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 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 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 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 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 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 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 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 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 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 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 pub fn bytes(length: usize) -> Vec<u8> {
1051 let mut rng = rand::thread_rng();
1052 (0..length).map(|_| rng.gen()).collect()
1053 }
1054
1055 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
1067pub struct Sequence {
1069 current: usize,
1070}
1071
1072impl Sequence {
1073 pub fn new() -> Self {
1075 Self { current: 0 }
1076 }
1077
1078 pub fn starting_at(value: usize) -> Self {
1080 Self {
1081 current: value.saturating_sub(1),
1082 }
1083 }
1084
1085 #[allow(clippy::should_implement_trait)]
1087 pub fn next(&mut self) -> usize {
1088 self.current += 1;
1089 self.current
1090 }
1091
1092 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 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 #[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 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 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 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}