diff --git a/docs/keywords/format.md b/docs/keywords/format.md index a5c4f15..4f84305 100644 --- a/docs/keywords/format.md +++ b/docs/keywords/format.md @@ -52,4 +52,5 @@ **USAGE:** `FORMAT(123.456, "C2")` → "$123.46" `FORMAT(NOW(), "yyyy-MM-dd HH:mm")` → "2024-01-15 14:30" -`FORMAT(0.15, "0%")` → "15%" \ No newline at end of file +`FORMAT(0.15, "0%")` → "15%" + diff --git a/src/services/keywords/format.rs b/src/services/keywords/format.rs index d085dd8..ca26177 100644 --- a/src/services/keywords/format.rs +++ b/src/services/keywords/format.rs @@ -191,3 +191,270 @@ fn apply_text_placeholders(value: &str, pattern: &str) -> String { result } + +#[cfg(test)] +mod tests { + use super::*; + use rhai::Engine; + + fn create_engine() -> Engine { + let mut engine = Engine::new(); + format_keyword(&mut engine); + engine + } + + #[test] + fn test_numeric_formatting_basic() { + let engine = create_engine(); + + // Teste formatação básica + assert_eq!( + engine.eval::("FORMAT 1234.567 \"n\"").unwrap(), + "1234.57" + ); + assert_eq!( + engine.eval::("FORMAT 1234.5 \"F\"").unwrap(), + "1234.50" + ); + assert_eq!( + engine.eval::("FORMAT 1234.567 \"f\"").unwrap(), + "1234.567" + ); + assert_eq!( + engine.eval::("FORMAT 0.85 \"0%\"").unwrap(), + "85%" + ); + } + + #[test] + fn test_numeric_formatting_with_locale() { + let engine = create_engine(); + + // Teste formatação numérica com locale + assert_eq!( + engine.eval::("FORMAT 1234.56 \"N[en]\"").unwrap(), + "1,234.56" + ); + assert_eq!( + engine.eval::("FORMAT 1234.56 \"N[pt]\"").unwrap(), + "1.234,56" + ); + assert_eq!( + engine.eval::("FORMAT 1234.56 \"N[fr]\"").unwrap(), + "1 234,56" + ); + } + + #[test] + fn test_currency_formatting() { + let engine = create_engine(); + + // Teste formatação monetária + assert_eq!( + engine.eval::("FORMAT 1234.56 \"C[en]\"").unwrap(), + "$1,234.56" + ); + assert_eq!( + engine.eval::("FORMAT 1234.56 \"C[pt]\"").unwrap(), + "R$ 1.234,56" + ); + assert_eq!( + engine.eval::("FORMAT 1234.56 \"C[fr]\"").unwrap(), + "€1 234,56" + ); + } + + #[test] + fn test_numeric_decimals_precision() { + let engine = create_engine(); + + // Teste precisão decimal + assert_eq!( + engine.eval::("FORMAT 1234.5678 \"N0[en]\"").unwrap(), + "1,235" + ); + assert_eq!( + engine.eval::("FORMAT 1234.5678 \"N1[en]\"").unwrap(), + "1,234.6" + ); + assert_eq!( + engine.eval::("FORMAT 1234.5678 \"N3[en]\"").unwrap(), + "1,234.568" + ); + assert_eq!( + engine.eval::("FORMAT 1234.5 \"C0[en]\"").unwrap(), + "$1,235" + ); + } + + #[test] + fn test_date_formatting() { + let engine = create_engine(); + + // Teste formatação de datas + let result = engine.eval::("FORMAT \"2024-03-15 14:30:25\" \"yyyy-MM-dd HH:mm:ss\"").unwrap(); + assert_eq!(result, "2024-03-15 14:30:25"); + + let result = engine.eval::("FORMAT \"2024-03-15 14:30:25\" \"dd/MM/yyyy\"").unwrap(); + assert_eq!(result, "15/03/2024"); + + let result = engine.eval::("FORMAT \"2024-03-15 14:30:25\" \"MM/dd/yy\"").unwrap(); + assert_eq!(result, "03/15/24"); + + let result = engine.eval::("FORMAT \"2024-03-15 14:30:25\" \"HH:mm\"").unwrap(); + assert_eq!(result, "14:30"); + } + + #[test] + fn test_date_formatting_12h() { + let engine = create_engine(); + + // Teste formato 12h + let result = engine.eval::("FORMAT \"2024-03-15 14:30:25\" \"hh:mm tt\"").unwrap(); + assert_eq!(result, "02:30 PM"); + + let result = engine.eval::("FORMAT \"2024-03-15 09:30:25\" \"hh:mm tt\"").unwrap(); + assert_eq!(result, "09:30 AM"); + + let result = engine.eval::("FORMAT \"2024-03-15 00:30:25\" \"h:mm t\"").unwrap(); + assert_eq!(result, "12:30 A"); + } + + #[test] + fn test_text_formatting() { + let engine = create_engine(); + + // Teste formatação de texto + assert_eq!( + engine.eval::("FORMAT \"hello\" \"Prefix: @\"").unwrap(), + "Prefix: hello" + ); + assert_eq!( + engine.eval::("FORMAT \"HELLO\" \"Result: &!\"").unwrap(), + "Result: hello!" + ); + assert_eq!( + engine.eval::("FORMAT \"hello\" \"RESULT: >\"").unwrap(), + "RESULT: HELLO" + ); + assert_eq!( + engine.eval::("FORMAT \"Hello\" \"<>\"").unwrap(), + "hello>" + ); + } + + #[test] + fn test_mixed_patterns() { + let engine = create_engine(); + + // Teste padrões mistos + assert_eq!( + engine.eval::("FORMAT \"hello\" \"@ World!\"").unwrap(), + "hello World!" + ); + assert_eq!( + engine.eval::("FORMAT \"test\" \"< & > ! @\"").unwrap(), + "test test TEST ! test" + ); + } + + #[test] + fn test_edge_cases() { + let engine = create_engine(); + + // Teste casos extremos + assert_eq!( + engine.eval::("FORMAT 0 \"n\"").unwrap(), + "0.00" + ); + assert_eq!( + engine.eval::("FORMAT -1234.56 \"N[en]\"").unwrap(), + "-1,234.56" + ); + assert_eq!( + engine.eval::("FORMAT \"\" \"@\"").unwrap(), + "" + ); + assert_eq!( + engine.eval::("FORMAT \"test\" \"\"").unwrap(), + "" + ); + } + + #[test] + fn test_invalid_patterns_fallback() { + let engine = create_engine(); + + // Teste padrões inválidos (devem fallback para string) + assert_eq!( + engine.eval::("FORMAT 123.45 \"invalid\"").unwrap(), + "123.45" + ); + assert_eq!( + engine.eval::("FORMAT \"text\" \"unknown\"").unwrap(), + "unknown" + ); + } + + #[test] + fn test_milliseconds_formatting() { + let engine = create_engine(); + + // Teste milissegundos + let result = engine.eval::("FORMAT \"2024-03-15 14:30:25.123\" \"HH:mm:ss.fff\"").unwrap(); + assert_eq!(result, "14:30:25.123"); + } + + #[test] + fn test_parse_pattern_function() { + // Teste direto da função parse_pattern + assert_eq!(parse_pattern("C[en]"), ("C".to_string(), 2, "en".to_string())); + assert_eq!(parse_pattern("N3[pt]"), ("N".to_string(), 3, "pt".to_string())); + assert_eq!(parse_pattern("C0[fr]"), ("C".to_string(), 0, "fr".to_string())); + assert_eq!(parse_pattern("N"), ("N".to_string(), 2, "en".to_string())); + assert_eq!(parse_pattern("C2"), ("C".to_string(), 2, "en".to_string())); + } + + #[test] + fn test_locale_functions() { + // Teste funções de locale + assert!(matches!(get_locale("en"), Locale::en)); + assert!(matches!(get_locale("pt"), Locale::pt)); + assert!(matches!(get_locale("fr"), Locale::fr)); + assert!(matches!(get_locale("invalid"), Locale::en)); // fallback + + assert_eq!(get_currency_symbol("en"), "$"); + assert_eq!(get_currency_symbol("pt"), "R$ "); + assert_eq!(get_currency_symbol("fr"), "€"); + assert_eq!(get_currency_symbol("invalid"), "$"); // fallback + } + + #[test] + fn test_apply_text_placeholders() { + // Teste direto da função apply_text_placeholders + assert_eq!(apply_text_placeholders("Hello", "@"), "Hello"); + assert_eq!(apply_text_placeholders("Hello", "&"), "hello"); + assert_eq!(apply_text_placeholders("Hello", ">"), "HELLO"); + assert_eq!(apply_text_placeholders("Hello", "Prefix: @!"), "Prefix: Hello!"); + assert_eq!(apply_text_placeholders("Hello", "<>"), "hello>"); + } + + #[test] + fn test_expression_parameters() { + let engine = create_engine(); + + // Teste com expressões como parâmetros + assert_eq!( + engine.eval::("let x = 1000.50; FORMAT x \"N[en]\"").unwrap(), + "1,000.50" + ); + assert_eq!( + engine.eval::("FORMAT (500 + 500) \"n\"").unwrap(), + "1000.00" + ); + assert_eq!( + engine.eval::("let pattern = \"@ World\"; FORMAT \"Hello\" pattern").unwrap(), + "Hello World" + ); + } +} \ No newline at end of file