sql_splitter/redactor/strategy/
fake.rs1use super::{RedactValue, Strategy, StrategyKind};
4use fake::faker::address::en::{CityName, StateName, StreetName, ZipCode};
5use fake::faker::company::en::CompanyName;
6use fake::faker::internet::en::{SafeEmail, Username};
7use fake::faker::lorem::en::{Paragraph, Sentence, Word};
8use fake::faker::name::en::{FirstName, LastName, Name};
9use fake::faker::phone_number::en::PhoneNumber;
10use fake::Fake;
11
12#[derive(Debug, Clone)]
14pub struct FakeStrategy {
15 generator: String,
16 locale: String,
17}
18
19impl FakeStrategy {
20 pub fn new(generator: String, locale: String) -> Self {
21 Self { generator, locale }
22 }
23
24 fn generate(&self, rng: &mut dyn rand::RngCore) -> String {
26 let mut seed = [0u8; 32];
28 rng.fill_bytes(&mut seed);
29 let mut fake_rng = rand::rngs::StdRng::from_seed(seed);
30
31 match self.generator.to_lowercase().as_str() {
32 "name" | "full_name" => Name().fake_with_rng(&mut fake_rng),
34 "first_name" => FirstName().fake_with_rng(&mut fake_rng),
35 "last_name" => LastName().fake_with_rng(&mut fake_rng),
36
37 "email" | "safe_email" => SafeEmail().fake_with_rng(&mut fake_rng),
39 "phone" | "phone_number" => PhoneNumber().fake_with_rng(&mut fake_rng),
40 "username" | "user_name" => Username().fake_with_rng(&mut fake_rng),
41
42 "address" | "street_address" => {
44 let street: String = StreetName().fake_with_rng(&mut fake_rng);
45 let city: String = CityName().fake_with_rng(&mut fake_rng);
46 let state: String = StateName().fake_with_rng(&mut fake_rng);
47 let zip: String = ZipCode().fake_with_rng(&mut fake_rng);
48 format!("{}, {}, {} {}", street, city, state, zip)
49 }
50 "street" | "street_name" => StreetName().fake_with_rng(&mut fake_rng),
51 "city" => CityName().fake_with_rng(&mut fake_rng),
52 "state" => StateName().fake_with_rng(&mut fake_rng),
53 "zip" | "zip_code" | "postal_code" => ZipCode().fake_with_rng(&mut fake_rng),
54 "country" => "United States".to_string(), "company" | "company_name" => CompanyName().fake_with_rng(&mut fake_rng),
58 "job_title" => {
59 let titles = [
61 "Software Engineer",
62 "Product Manager",
63 "Data Analyst",
64 "Designer",
65 "Marketing Manager",
66 "Sales Representative",
67 "Customer Support",
68 "Operations Manager",
69 ];
70 let idx = fake_rng.random_range(0..titles.len());
71 titles[idx].to_string()
72 }
73
74 "url" => format!(
76 "https://example{}.com/{}",
77 fake_rng.random_range(1..1000),
78 Word().fake_with_rng::<String, _>(&mut fake_rng)
79 ),
80 "ip" | "ip_address" | "ipv4" => {
81 format!(
82 "{}.{}.{}.{}",
83 fake_rng.random_range(1..255),
84 fake_rng.random_range(0..255),
85 fake_rng.random_range(0..255),
86 fake_rng.random_range(1..255)
87 )
88 }
89 "ipv6" => {
90 format!(
91 "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
92 fake_rng.random_range(0..0xFFFF_u16),
93 fake_rng.random_range(0..0xFFFF_u16),
94 fake_rng.random_range(0..0xFFFF_u16),
95 fake_rng.random_range(0..0xFFFF_u16),
96 fake_rng.random_range(0..0xFFFF_u16),
97 fake_rng.random_range(0..0xFFFF_u16),
98 fake_rng.random_range(0..0xFFFF_u16),
99 fake_rng.random_range(0..0xFFFF_u16)
100 )
101 }
102
103 "uuid" => {
105 format!(
106 "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
107 fake_rng.random::<u32>(),
108 fake_rng.random::<u16>(),
109 (fake_rng.random::<u16>() & 0x0FFF) | 0x4000, (fake_rng.random::<u16>() & 0x3FFF) | 0x8000, fake_rng.random::<u64>() & 0xFFFFFFFFFFFF_u64
112 )
113 }
114
115 "date" => {
117 let year = fake_rng.random_range(1970..2024);
118 let month = fake_rng.random_range(1..=12);
119 let day = fake_rng.random_range(1..=28);
120 format!("{:04}-{:02}-{:02}", year, month, day)
121 }
122 "datetime" | "date_time" => {
123 let year = fake_rng.random_range(1970..2024);
124 let month = fake_rng.random_range(1..=12);
125 let day = fake_rng.random_range(1..=28);
126 let hour = fake_rng.random_range(0..24);
127 let minute = fake_rng.random_range(0..60);
128 let second = fake_rng.random_range(0..60);
129 format!(
130 "{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
131 year, month, day, hour, minute, second
132 )
133 }
134 "time" => {
135 let hour = fake_rng.random_range(0..24);
136 let minute = fake_rng.random_range(0..60);
137 let second = fake_rng.random_range(0..60);
138 format!("{:02}:{:02}:{:02}", hour, minute, second)
139 }
140
141 "credit_card" => {
143 format!(
145 "{:04}-{:04}-{:04}-{:04}",
146 fake_rng.random_range(1000..9999),
147 fake_rng.random_range(1000..9999),
148 fake_rng.random_range(1000..9999),
149 fake_rng.random_range(1000..9999)
150 )
151 }
152 "iban" => {
153 format!(
155 "DE{:02}{:04}{:04}{:04}{:04}{:02}",
156 fake_rng.random_range(10..99),
157 fake_rng.random_range(1000..9999),
158 fake_rng.random_range(1000..9999),
159 fake_rng.random_range(1000..9999),
160 fake_rng.random_range(1000..9999),
161 fake_rng.random_range(10..99)
162 )
163 }
164
165 "ssn" => {
167 format!(
168 "{:03}-{:02}-{:04}",
169 fake_rng.random_range(100..999),
170 fake_rng.random_range(10..99),
171 fake_rng.random_range(1000..9999)
172 )
173 }
174
175 "lorem" | "paragraph" => Paragraph(3..5).fake_with_rng(&mut fake_rng),
177 "sentence" => Sentence(5..10).fake_with_rng(&mut fake_rng),
178 "word" => Word().fake_with_rng(&mut fake_rng),
179
180 _ => format!("FAKE_{}", fake_rng.random_range(10000..99999)),
182 }
183 }
184}
185
186impl Strategy for FakeStrategy {
187 fn apply(&self, value: &RedactValue, rng: &mut dyn rand::RngCore) -> RedactValue {
188 match value {
189 RedactValue::Null => RedactValue::Null,
190 _ => RedactValue::String(self.generate(rng)),
191 }
192 }
193
194 fn kind(&self) -> StrategyKind {
195 StrategyKind::Fake {
196 generator: self.generator.clone(),
197 }
198 }
199}
200
201use rand::{Rng, SeedableRng};
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_fake_name() {
209 let strategy = FakeStrategy::new("name".to_string(), "en".to_string());
210 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
211
212 let result = strategy.apply(&RedactValue::String("John Doe".to_string()), &mut rng);
213 match result {
214 RedactValue::String(s) => {
215 assert!(!s.is_empty());
216 assert!(s.contains(' ')); }
218 _ => panic!("Expected String"),
219 }
220 }
221
222 #[test]
223 fn test_fake_email() {
224 let strategy = FakeStrategy::new("email".to_string(), "en".to_string());
225 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
226
227 let result = strategy.apply(
228 &RedactValue::String("real@example.com".to_string()),
229 &mut rng,
230 );
231 match result {
232 RedactValue::String(s) => {
233 assert!(s.contains('@'));
234 }
235 _ => panic!("Expected String"),
236 }
237 }
238
239 #[test]
240 fn test_fake_phone() {
241 let strategy = FakeStrategy::new("phone".to_string(), "en".to_string());
242 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
243
244 let result = strategy.apply(&RedactValue::String("555-123-4567".to_string()), &mut rng);
245 match result {
246 RedactValue::String(s) => {
247 assert!(!s.is_empty());
248 }
249 _ => panic!("Expected String"),
250 }
251 }
252
253 #[test]
254 fn test_fake_uuid() {
255 let strategy = FakeStrategy::new("uuid".to_string(), "en".to_string());
256 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
257
258 let result = strategy.apply(
259 &RedactValue::String("550e8400-e29b-41d4-a716-446655440000".to_string()),
260 &mut rng,
261 );
262 match result {
263 RedactValue::String(s) => {
264 assert!(s.contains('-'));
266 assert_eq!(s.len(), 36);
267 }
268 _ => panic!("Expected String"),
269 }
270 }
271
272 #[test]
273 fn test_fake_null() {
274 let strategy = FakeStrategy::new("name".to_string(), "en".to_string());
275 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
276
277 let result = strategy.apply(&RedactValue::Null, &mut rng);
278 assert!(matches!(result, RedactValue::Null));
279 }
280
281 #[test]
282 fn test_fake_date() {
283 let strategy = FakeStrategy::new("date".to_string(), "en".to_string());
284 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
285
286 let result = strategy.apply(&RedactValue::String("2024-01-15".to_string()), &mut rng);
287 match result {
288 RedactValue::String(s) => {
289 assert_eq!(s.len(), 10);
291 assert!(s.contains('-'));
292 }
293 _ => panic!("Expected String"),
294 }
295 }
296
297 #[test]
298 fn test_fake_credit_card() {
299 let strategy = FakeStrategy::new("credit_card".to_string(), "en".to_string());
300 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
301
302 let result = strategy.apply(
303 &RedactValue::String("4532-0151-1283-0366".to_string()),
304 &mut rng,
305 );
306 match result {
307 RedactValue::String(s) => {
308 assert_eq!(s.len(), 19);
310 assert_eq!(s.matches('-').count(), 3);
311 }
312 _ => panic!("Expected String"),
313 }
314 }
315}