datafake_rs/operators/
fake.rs

1use crate::error::{DataFakeError, Result};
2use chrono::Utc;
3use datalogic_rs::{ContextStack, Evaluator, Operator};
4use fake::faker::address::en::{
5    CityName, CountryCode, CountryName, Latitude, Longitude, PostCode, StateAbbr, StateName,
6    StreetName, StreetSuffix, ZipCode,
7};
8use fake::faker::barcode::en::{Isbn10, Isbn13};
9use fake::faker::company::en::{
10    Bs, BsAdj, BsNoun, BsVerb, CatchPhrase, CompanyName, CompanySuffix, Industry, Profession,
11};
12use fake::faker::creditcard::en::CreditCardNumber;
13use fake::faker::currency::en::{CurrencyCode, CurrencyName, CurrencySymbol};
14use fake::faker::filesystem::en::{DirPath, FileExtension, FileName, FilePath};
15use fake::faker::finance::en::Bic;
16use fake::faker::internet::en::{
17    DomainSuffix, FreeEmail, IPv4, IPv6, MACAddress, Password, SafeEmail, UserAgent, Username,
18};
19use fake::faker::lorem::en::{Paragraph, Sentence, Word, Words};
20use fake::faker::name::en::{FirstName, LastName, NameWithTitle, Suffix, Title};
21use fake::faker::phone_number::en::{CellNumber, PhoneNumber};
22use fake::{Fake, Faker};
23use rand::Rng;
24use serde_json::Value;
25
26pub struct FakeOperator;
27
28impl Operator for FakeOperator {
29    fn evaluate(
30        &self,
31        args: &[Value],
32        _context: &mut ContextStack,
33        _evaluator: &dyn Evaluator,
34    ) -> std::result::Result<Value, datalogic_rs::Error> {
35        // Call the existing generate method and convert error
36        FakeOperator::generate(args).map_err(|e| datalogic_rs::Error::Custom(e.to_string()))
37    }
38}
39
40impl FakeOperator {
41    pub fn generate(args: &[Value]) -> Result<Value> {
42        if args.is_empty() {
43            return Err(DataFakeError::FakeOperatorError(
44                "Fake operator requires at least one argument".to_string(),
45            ));
46        }
47
48        let method = args[0].as_str().ok_or_else(|| {
49            DataFakeError::FakeOperatorError("First argument must be a string".to_string())
50        })?;
51
52        let _locale = args.get(1).and_then(|v| v.as_str()).unwrap_or("en");
53
54        match method {
55            // Numeric types with optional range
56            "u8" => Self::generate_u8(args),
57            "u16" => Self::generate_u16(args),
58            "u32" => Self::generate_u32(args),
59            "u64" => Self::generate_u64(args),
60            "i8" => Self::generate_i8(args),
61            "i16" => Self::generate_i16(args),
62            "i32" => Self::generate_i32(args),
63            "i64" => Self::generate_i64(args),
64            "f32" => Self::generate_f32(args),
65            "f64" => Self::generate_f64(args),
66
67            // Boolean
68            "bool" | "boolean" => Ok(Value::Bool(rand::rng().random())),
69
70            // UUID
71            "uuid" => Ok(Value::String(fake::uuid::UUIDv4.fake())),
72
73            // Address related
74            "street_address" => {
75                // Generate a street address by combining components
76                let street_num: u16 = (1..9999).fake();
77                let street = StreetName().fake::<String>();
78                let suffix = StreetSuffix().fake::<String>();
79                Ok(Value::String(format!("{street_num} {street} {suffix}")))
80            }
81            "city" | "city_name" => Ok(Value::String(CityName().fake())),
82            "country_name" => Ok(Value::String(CountryName().fake())),
83            "country_code" => Ok(Value::String(CountryCode().fake())),
84            "state_name" => Ok(Value::String(StateName().fake())),
85            "state_abbr" => Ok(Value::String(StateAbbr().fake())),
86            "zip_code" | "zip" => Ok(Value::String(ZipCode().fake())),
87            "post_code" | "postcode" | "postal_code" => Ok(Value::String(PostCode().fake())),
88            "latitude" => Ok(Value::Number(
89                serde_json::Number::from_f64(Latitude().fake::<f64>()).unwrap(),
90            )),
91            "longitude" => Ok(Value::Number(
92                serde_json::Number::from_f64(Longitude().fake::<f64>()).unwrap(),
93            )),
94            "street_name" => Ok(Value::String(StreetName().fake())),
95            "street_suffix" => Ok(Value::String(StreetSuffix().fake())),
96
97            // Name related
98            "name" | "full_name" => {
99                // For now, use English locale only
100                use fake::faker::name::en::Name;
101                Ok(Value::String(Name().fake()))
102            }
103            "first_name" => Ok(Value::String(FirstName().fake())),
104            "last_name" => Ok(Value::String(LastName().fake())),
105            "name_with_title" => Ok(Value::String(NameWithTitle().fake())),
106            "title" => Ok(Value::String(Title().fake())),
107            "suffix" => Ok(Value::String(Suffix().fake())),
108
109            // Company related
110            "company_name" => Ok(Value::String(CompanyName().fake())),
111            "company_suffix" => Ok(Value::String(CompanySuffix().fake())),
112            "industry" => Ok(Value::String(Industry().fake())),
113            "profession" => Ok(Value::String(Profession().fake())),
114            "catch_phrase" => Ok(Value::String(CatchPhrase().fake())),
115            "bs" => Ok(Value::String(Bs().fake())),
116            "bs_adj" => Ok(Value::String(BsAdj().fake())),
117            "bs_noun" => Ok(Value::String(BsNoun().fake())),
118            "bs_verb" => Ok(Value::String(BsVerb().fake())),
119
120            // Internet related
121            "email" | "safe_email" => Ok(Value::String(SafeEmail().fake())),
122            "free_email" => Ok(Value::String(FreeEmail().fake())),
123            "username" => Ok(Value::String(Username().fake())),
124            "password" => {
125                let min_len = args.get(1).and_then(|v| v.as_u64()).unwrap_or(8) as usize;
126                let max_len = args.get(2).and_then(|v| v.as_u64()).unwrap_or(20) as usize;
127                Ok(Value::String(Password(min_len..max_len).fake()))
128            }
129            "domain_suffix" => Ok(Value::String(DomainSuffix().fake())),
130            "domain_name" => {
131                // Generate a domain name
132                let words: Vec<String> = Words(1..2).fake();
133                let suffix = DomainSuffix().fake::<String>();
134                Ok(Value::String(format!(
135                    "{}.{}",
136                    words.join("").to_lowercase(),
137                    suffix
138                )))
139            }
140            "ipv4" => Ok(Value::String(IPv4().fake())),
141            "ipv6" => Ok(Value::String(IPv6().fake())),
142            "mac_address" => Ok(Value::String(MACAddress().fake())),
143            "user_agent" => Ok(Value::String(UserAgent().fake())),
144
145            // Phone
146            "phone_number" => Ok(Value::String(PhoneNumber().fake())),
147            "cell_number" => Ok(Value::String(CellNumber().fake())),
148
149            // Finance
150            "bic" => {
151                // Support optional length parameter (8 or 11)
152                let length = args.get(1).and_then(|v| v.as_u64());
153                match length {
154                    Some(8) => Self::generate_bic_fixed(8),
155                    Some(11) => Self::generate_bic_fixed(11),
156                    Some(_) => Err(DataFakeError::FakeOperatorError(
157                        "BIC length must be 8 or 11".to_string(),
158                    )),
159                    None => Ok(Value::String(Bic().fake())), // Default: random 8 or 11
160                }
161            }
162            "bic8" => Self::generate_bic_fixed(8),
163            "bic11" => Self::generate_bic_fixed(11),
164            "credit_card_number" => Ok(Value::String(CreditCardNumber().fake())),
165
166            // Currency
167            "currency_code" => Ok(Value::String(CurrencyCode().fake())),
168            "currency_name" => Ok(Value::String(CurrencyName().fake())),
169            "currency_symbol" => Ok(Value::String(CurrencySymbol().fake())),
170
171            // Lorem
172            "word" => Ok(Value::String(Word().fake())),
173            "words" => {
174                let count = args.get(1).and_then(|v| v.as_u64()).unwrap_or(5) as usize;
175                let words: Vec<String> = Words(count..count + 1).fake();
176                Ok(Value::String(words.join(" ")))
177            }
178            "sentence" => {
179                let min_words = args.get(1).and_then(|v| v.as_u64()).unwrap_or(4) as usize;
180                let max_words = args.get(2).and_then(|v| v.as_u64()).unwrap_or(10) as usize;
181                Ok(Value::String(Sentence(min_words..max_words).fake()))
182            }
183            "paragraph" => {
184                let min_sentences = args.get(1).and_then(|v| v.as_u64()).unwrap_or(3) as usize;
185                let max_sentences = args.get(2).and_then(|v| v.as_u64()).unwrap_or(7) as usize;
186                Ok(Value::String(
187                    Paragraph(min_sentences..max_sentences).fake(),
188                ))
189            }
190
191            // Barcode
192            "isbn10" => Ok(Value::String(Isbn10().fake())),
193            "isbn13" => Ok(Value::String(Isbn13().fake())),
194
195            // Filesystem
196            "file_name" => Ok(Value::String(FileName().fake())),
197            "file_extension" => Ok(Value::String(FileExtension().fake())),
198            "dir_path" => Ok(Value::String(DirPath().fake())),
199            "file_path" => Ok(Value::String(FilePath().fake())),
200
201            // Date/Time - Generate ISO8601 formatted datetime
202            "datetime" | "iso8601_datetime" => {
203                let now = Utc::now();
204                Ok(Value::String(now.to_rfc3339()))
205            }
206            "date" => {
207                // Generate date in specified format
208                let format = args.get(1).and_then(|v| v.as_str()).unwrap_or("%Y-%m-%d");
209                let now = Utc::now();
210                Ok(Value::String(now.format(format).to_string()))
211            }
212            "time" => {
213                // Generate time in HH:MM:SS format
214                let mut rng = rand::rng();
215                let hour = rng.random_range(0..24);
216                let minute = rng.random_range(0..60);
217                let second = rng.random_range(0..60);
218                Ok(Value::String(format!("{hour:02}:{minute:02}:{second:02}")))
219            }
220            "month_name" => {
221                // Generate a month name
222                let months = [
223                    "January",
224                    "February",
225                    "March",
226                    "April",
227                    "May",
228                    "June",
229                    "July",
230                    "August",
231                    "September",
232                    "October",
233                    "November",
234                    "December",
235                ];
236                let mut rng = rand::rng();
237                let idx = rng.random_range(0..months.len());
238                Ok(Value::String(months[idx].to_string()))
239            }
240
241            // Financial - Custom types for MX messages
242            "iban" => {
243                let country = args.get(1).and_then(|v| v.as_str()).unwrap_or("DE");
244                let mut rng = rand::rng();
245                let check = format!("{:02}", rng.random_range(10..99));
246                let account: String = (0..18)
247                    .map(|_| rng.random_range(0..10).to_string())
248                    .collect();
249                Ok(Value::String(format!("{country}{check}{account}")))
250            }
251            "lei" => {
252                // Generate a realistic LEI (18 uppercase alphanumeric + 2 check digits)
253                let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
254                let mut rng = rand::rng();
255                let lei: String = (0..18)
256                    .map(|_| chars.chars().nth(rng.random_range(0..chars.len())).unwrap())
257                    .collect();
258                let check = format!("{:02}", rng.random_range(10..99));
259                Ok(Value::String(format!("{lei}{check}")))
260            }
261            "alphanumeric" => {
262                let min_len = args.get(1).and_then(|v| v.as_u64()).unwrap_or(10) as usize;
263                let max_len = args
264                    .get(2)
265                    .and_then(|v| v.as_u64())
266                    .unwrap_or(min_len as u64) as usize;
267                let mut rng = rand::rng();
268                let len = if min_len == max_len {
269                    min_len
270                } else {
271                    rng.random_range(min_len..=max_len)
272                };
273                let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
274                let result: String = (0..len)
275                    .map(|_| chars.chars().nth(rng.random_range(0..chars.len())).unwrap())
276                    .collect();
277                Ok(Value::String(result))
278            }
279
280            // Enum/Choice - pick one value from provided options
281            "enum" | "pick" | "choice" => {
282                if args.len() < 2 {
283                    return Err(DataFakeError::FakeOperatorError(
284                        "enum requires at least one option".to_string(),
285                    ));
286                }
287                let options = &args[1..];
288                let mut rng = rand::rng();
289                let idx = rng.random_range(0..options.len());
290                Ok(options[idx].clone())
291            }
292
293            // Regex - Handle simple regex patterns for selecting from options
294            "regex" => {
295                if let Some(Value::String(pattern)) = args.get(1) {
296                    // Simple handling for common patterns like "(A|B|C)"
297                    if pattern.starts_with('(') && pattern.ends_with(')') {
298                        let inner = &pattern[1..pattern.len() - 1];
299                        let options: Vec<&str> = inner.split('|').collect();
300                        if !options.is_empty() {
301                            let mut rng = rand::rng();
302                            let idx = rng.random_range(0..options.len());
303                            return Ok(Value::String(options[idx].to_string()));
304                        }
305                    }
306                    // For other patterns, just return a placeholder
307                    Ok(Value::String("REGEX_PATTERN".to_string()))
308                } else {
309                    Err(DataFakeError::FakeOperatorError(
310                        "regex requires a pattern argument".to_string(),
311                    ))
312                }
313            }
314
315            _ => Err(DataFakeError::FakeOperatorError(format!(
316                "Unknown fake method: {method}"
317            ))),
318        }
319    }
320
321    fn generate_u8(args: &[Value]) -> Result<Value> {
322        match args.len() {
323            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<u8>()))),
324            3 => {
325                let min = args[1].as_u64().unwrap_or(0) as u8;
326                let max = args[2].as_u64().unwrap_or(255) as u8;
327                Ok(Value::Number(serde_json::Number::from(
328                    rand::rng().random_range(min..=max),
329                )))
330            }
331            _ => Err(DataFakeError::FakeOperatorError(
332                "u8 requires either 1 or 3 arguments".to_string(),
333            )),
334        }
335    }
336
337    fn generate_u16(args: &[Value]) -> Result<Value> {
338        match args.len() {
339            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<u16>()))),
340            3 => {
341                let min = args[1].as_u64().unwrap_or(0) as u16;
342                let max = args[2].as_u64().unwrap_or(65535) as u16;
343                Ok(Value::Number(serde_json::Number::from(
344                    rand::rng().random_range(min..=max),
345                )))
346            }
347            _ => Err(DataFakeError::FakeOperatorError(
348                "u16 requires either 1 or 3 arguments".to_string(),
349            )),
350        }
351    }
352
353    fn generate_u32(args: &[Value]) -> Result<Value> {
354        match args.len() {
355            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<u32>()))),
356            3 => {
357                let min = args[1].as_u64().unwrap_or(0) as u32;
358                let max = args[2].as_u64().unwrap_or(u32::MAX as u64) as u32;
359                Ok(Value::Number(serde_json::Number::from(
360                    rand::rng().random_range(min..=max),
361                )))
362            }
363            _ => Err(DataFakeError::FakeOperatorError(
364                "u32 requires either 1 or 3 arguments".to_string(),
365            )),
366        }
367    }
368
369    fn generate_u64(args: &[Value]) -> Result<Value> {
370        match args.len() {
371            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<u64>()))),
372            3 => {
373                let min = args[1].as_u64().unwrap_or(0);
374                let max = args[2].as_u64().unwrap_or(u64::MAX);
375                Ok(Value::Number(serde_json::Number::from(
376                    rand::rng().random_range(min..=max),
377                )))
378            }
379            _ => Err(DataFakeError::FakeOperatorError(
380                "u64 requires either 1 or 3 arguments".to_string(),
381            )),
382        }
383    }
384
385    fn generate_i8(args: &[Value]) -> Result<Value> {
386        match args.len() {
387            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<i8>()))),
388            3 => {
389                let min = args[1].as_i64().unwrap_or(i8::MIN as i64) as i8;
390                let max = args[2].as_i64().unwrap_or(i8::MAX as i64) as i8;
391                Ok(Value::Number(serde_json::Number::from(
392                    rand::rng().random_range(min..=max),
393                )))
394            }
395            _ => Err(DataFakeError::FakeOperatorError(
396                "i8 requires either 1 or 3 arguments".to_string(),
397            )),
398        }
399    }
400
401    fn generate_i16(args: &[Value]) -> Result<Value> {
402        match args.len() {
403            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<i16>()))),
404            3 => {
405                let min = args[1].as_i64().unwrap_or(i16::MIN as i64) as i16;
406                let max = args[2].as_i64().unwrap_or(i16::MAX as i64) as i16;
407                Ok(Value::Number(serde_json::Number::from(
408                    rand::rng().random_range(min..=max),
409                )))
410            }
411            _ => Err(DataFakeError::FakeOperatorError(
412                "i16 requires either 1 or 3 arguments".to_string(),
413            )),
414        }
415    }
416
417    fn generate_i32(args: &[Value]) -> Result<Value> {
418        match args.len() {
419            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<i32>()))),
420            3 => {
421                let min = args[1].as_i64().unwrap_or(i32::MIN as i64) as i32;
422                let max = args[2].as_i64().unwrap_or(i32::MAX as i64) as i32;
423                Ok(Value::Number(serde_json::Number::from(
424                    rand::rng().random_range(min..=max),
425                )))
426            }
427            _ => Err(DataFakeError::FakeOperatorError(
428                "i32 requires either 1 or 3 arguments".to_string(),
429            )),
430        }
431    }
432
433    fn generate_i64(args: &[Value]) -> Result<Value> {
434        match args.len() {
435            1 => Ok(Value::Number(serde_json::Number::from(Faker.fake::<i64>()))),
436            3 => {
437                let min = args[1].as_i64().unwrap_or(i64::MIN);
438                let max = args[2].as_i64().unwrap_or(i64::MAX);
439                Ok(Value::Number(serde_json::Number::from(
440                    rand::rng().random_range(min..=max),
441                )))
442            }
443            _ => Err(DataFakeError::FakeOperatorError(
444                "i64 requires either 1 or 3 arguments".to_string(),
445            )),
446        }
447    }
448
449    fn generate_f32(args: &[Value]) -> Result<Value> {
450        match args.len() {
451            1 => Ok(Value::Number(
452                serde_json::Number::from_f64(Faker.fake::<f32>() as f64).unwrap(),
453            )),
454            3 => {
455                let min = args[1].as_f64().unwrap_or(0.0) as f32;
456                let max = args[2].as_f64().unwrap_or(1.0) as f32;
457                let value = rand::rng().random_range(min..=max);
458                Ok(Value::Number(
459                    serde_json::Number::from_f64(value as f64).unwrap(),
460                ))
461            }
462            _ => Err(DataFakeError::FakeOperatorError(
463                "f32 requires either 1 or 3 arguments".to_string(),
464            )),
465        }
466    }
467
468    fn generate_f64(args: &[Value]) -> Result<Value> {
469        match args.len() {
470            1 => Ok(Value::Number(
471                serde_json::Number::from_f64(Faker.fake::<f64>()).unwrap(),
472            )),
473            3 => {
474                let min = args[1].as_f64().unwrap_or(0.0);
475                let max = args[2].as_f64().unwrap_or(1.0);
476                let value = rand::rng().random_range(min..=max);
477                Ok(Value::Number(serde_json::Number::from_f64(value).unwrap()))
478            }
479            _ => Err(DataFakeError::FakeOperatorError(
480                "f64 requires either 1 or 3 arguments".to_string(),
481            )),
482        }
483    }
484
485    fn generate_bic_fixed(length: u64) -> Result<Value> {
486        use rand::seq::IndexedRandom;
487        let mut rng = rand::rng();
488
489        // Constants for BIC generation
490        const ALPHABET: &[char; 26] = &[
491            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
492            'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
493        ];
494        const VOWELS: &[char; 5] = &['A', 'E', 'I', 'O', 'U'];
495        const ISO3166: &[&str] = &[
496            "AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT",
497            "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL",
498            "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BU", "BV", "BW", "BY", "BZ", "CA", "CC",
499            "CD", "CE", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CP", "CR", "CS",
500            "CU", "CV", "CW", "CX", "CY", "CZ", "DD", "DE", "DG", "DJ", "DK", "DM", "DO", "DZ",
501            "EA", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "EU", "FI", "FJ", "FK", "FM", "FO",
502            "FR", "FX", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP",
503            "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "IC",
504            "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP",
505            "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC",
506            "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG",
507            "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW",
508            "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NT",
509            "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS",
510            "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE",
511            "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SU", "SV",
512            "SX", "SY", "SZ", "TA", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN",
513            "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC",
514            "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZR", "ZW",
515        ];
516
517        // Generate base 8-character BIC: AAAAVCC1
518        let base_bic = format!(
519            "{}{}{}{}{}{}1",
520            *ALPHABET.choose(&mut rng).unwrap(),
521            *ALPHABET.choose(&mut rng).unwrap(),
522            *ALPHABET.choose(&mut rng).unwrap(),
523            *VOWELS.choose(&mut rng).unwrap(),
524            *ISO3166.choose(&mut rng).unwrap(),
525            *ALPHABET.choose(&mut rng).unwrap(),
526        );
527
528        let bic = if length == 11 {
529            // Add branch code suffix (3 chars)
530            let prob: i8 = rng.random_range(0..100);
531            let suffix = if prob < 70 {
532                // 70% chance: numeric branch code
533                format!(
534                    "{}{}{}",
535                    rng.random_range('0'..='9'),
536                    rng.random_range('0'..='9'),
537                    rng.random_range('0'..='9'),
538                )
539            } else {
540                // 30% chance: alphabetic branch code
541                format!(
542                    "{}{}{}",
543                    *ALPHABET.choose(&mut rng).unwrap(),
544                    *VOWELS.choose(&mut rng).unwrap(),
545                    *ALPHABET.choose(&mut rng).unwrap(),
546                )
547            };
548            format!("{}{}", base_bic, suffix)
549        } else {
550            base_bic
551        };
552
553        Ok(Value::String(bic))
554    }
555}
556
557#[cfg(test)]
558mod tests {
559    use super::*;
560    use serde_json::json;
561
562    #[test]
563    fn test_generate_uuid() {
564        let args = vec![json!("uuid")];
565        let result = FakeOperator::generate(&args).unwrap();
566        assert!(result.is_string());
567        assert_eq!(result.as_str().unwrap().len(), 36); // UUID v4 format
568    }
569
570    #[test]
571    fn test_generate_numeric_no_range() {
572        let args = vec![json!("u8")];
573        let result = FakeOperator::generate(&args).unwrap();
574        assert!(result.is_number());
575    }
576
577    #[test]
578    fn test_generate_numeric_with_range() {
579        let args = vec![json!("u8"), json!(10), json!(20)];
580        let result = FakeOperator::generate(&args).unwrap();
581        assert!(result.is_number());
582        let value = result.as_u64().unwrap();
583        assert!((10..=20).contains(&value));
584    }
585
586    #[test]
587    fn test_generate_name_with_locale() {
588        let args = vec![json!("name"), json!("en_US")];
589        let result = FakeOperator::generate(&args).unwrap();
590        assert!(result.is_string());
591        assert!(!result.as_str().unwrap().is_empty());
592    }
593
594    #[test]
595    fn test_generate_email() {
596        let args = vec![json!("email")];
597        let result = FakeOperator::generate(&args).unwrap();
598        assert!(result.is_string());
599        let email = result.as_str().unwrap();
600        assert!(email.contains('@'));
601    }
602
603    #[test]
604    fn test_generate_password_with_length() {
605        let args = vec![json!("password"), json!(10), json!(15)];
606        let result = FakeOperator::generate(&args).unwrap();
607        assert!(result.is_string());
608        let password = result.as_str().unwrap();
609        assert!(password.len() >= 10 && password.len() <= 15);
610    }
611
612    #[test]
613    fn test_invalid_method() {
614        let args = vec![json!("invalid_method")];
615        let result = FakeOperator::generate(&args);
616        assert!(result.is_err());
617    }
618
619    #[test]
620    fn test_empty_args() {
621        let args = vec![];
622        let result = FakeOperator::generate(&args);
623        assert!(result.is_err());
624    }
625
626    #[test]
627    fn test_generate_bic_default() {
628        let args = vec![json!("bic")];
629        let result = FakeOperator::generate(&args).unwrap();
630        assert!(result.is_string());
631        let bic = result.as_str().unwrap();
632        assert!(bic.len() == 8 || bic.len() == 11);
633    }
634
635    #[test]
636    fn test_generate_bic8() {
637        let args = vec![json!("bic8")];
638        let result = FakeOperator::generate(&args).unwrap();
639        assert!(result.is_string());
640        let bic = result.as_str().unwrap();
641        assert_eq!(bic.len(), 8);
642    }
643
644    #[test]
645    fn test_generate_bic11() {
646        let args = vec![json!("bic11")];
647        let result = FakeOperator::generate(&args).unwrap();
648        assert!(result.is_string());
649        let bic = result.as_str().unwrap();
650        assert_eq!(bic.len(), 11);
651    }
652
653    #[test]
654    fn test_generate_bic_with_length_8() {
655        let args = vec![json!("bic"), json!(8)];
656        let result = FakeOperator::generate(&args).unwrap();
657        assert!(result.is_string());
658        let bic = result.as_str().unwrap();
659        assert_eq!(bic.len(), 8);
660    }
661
662    #[test]
663    fn test_generate_bic_with_length_11() {
664        let args = vec![json!("bic"), json!(11)];
665        let result = FakeOperator::generate(&args).unwrap();
666        assert!(result.is_string());
667        let bic = result.as_str().unwrap();
668        assert_eq!(bic.len(), 11);
669    }
670
671    #[test]
672    fn test_generate_bic_with_invalid_length() {
673        let args = vec![json!("bic"), json!(10)];
674        let result = FakeOperator::generate(&args);
675        assert!(result.is_err());
676        match result {
677            Err(DataFakeError::FakeOperatorError(msg)) => {
678                assert!(msg.contains("BIC length must be 8 or 11"));
679            }
680            _ => panic!("Expected FakeOperatorError with specific message"),
681        }
682    }
683}