use proptest::prelude::*;
use serializer::llm::{DxDocument, DxLlmValue, DxSection, LlmSerializer};
fn arb_large_section() -> impl Strategy<Value = DxSection> {
(11..20_usize).prop_flat_map(|row_count| {
let schema = vec!["id".to_string(), "name".to_string()];
let rows = (0..row_count)
.map(|i| {
vec![
DxLlmValue::Num(i as f64),
DxLlmValue::Str(format!("item{}", i)),
]
})
.collect();
Just(DxSection { schema, rows })
})
}
fn arb_log_section() -> impl Strategy<Value = DxSection> {
(1..5_usize).prop_flat_map(|row_count| {
let schema = vec![
"timestamp".to_string(),
"level".to_string(),
"message".to_string(),
];
let rows = (0..row_count)
.map(|i| {
vec![
DxLlmValue::Str(format!("2025-01-{}T10:00:00Z", i + 1)),
DxLlmValue::Str("info".to_string()),
DxLlmValue::Str(format!("msg{}", i)),
]
})
.collect();
Just(DxSection { schema, rows })
})
}
fn arb_complex_section() -> impl Strategy<Value = DxSection> {
(1..5_usize).prop_flat_map(|row_count| {
let schema = vec!["id".to_string(), "data".to_string()];
let rows = (0..row_count)
.map(|i| {
vec![
DxLlmValue::Num(i as f64),
DxLlmValue::Arr(vec![
DxLlmValue::Str("a".to_string()),
DxLlmValue::Str("b".to_string()),
]),
]
})
.collect();
Just(DxSection { schema, rows })
})
}
fn arb_simple_section() -> impl Strategy<Value = DxSection> {
(1..5_usize).prop_flat_map(|row_count| {
let schema = vec!["id".to_string(), "value".to_string()];
let rows = (0..row_count)
.map(|i| {
vec![
DxLlmValue::Num(i as f64),
DxLlmValue::Str(format!("val{}", i)),
]
})
.collect();
Just(DxSection { schema, rows })
})
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn large_tables_use_newline_separator(section in arb_large_section()) {
let serializer = LlmSerializer::new();
let mut doc = DxDocument::new();
doc.sections.insert('d', section.clone());
let output = serializer.serialize(&doc);
let lines: Vec<&str> = output.lines().collect();
prop_assert!(lines.len() > section.rows.len(), "Expected multi-line format for large table");
let table_content = output.split('[').nth(1).unwrap_or("");
prop_assert!(!table_content.contains(", "), "Large table should not use comma separator");
prop_assert!(!table_content.contains("; "), "Large table should not use semicolon separator");
prop_assert!(!table_content.contains(": "), "Large table should not use colon separator");
}
#[test]
fn log_tables_use_colon_separator(section in arb_log_section()) {
let serializer = LlmSerializer::new();
let mut doc = DxDocument::new();
doc.sections.insert('d', section.clone());
let output = serializer.serialize(&doc);
let table_content = output.split('[').nth(1).unwrap_or("");
if section.rows.len() > 1 {
prop_assert!(table_content.contains(": "), "Log table should use colon separator: {}", output);
}
let lines: Vec<&str> = output.lines().collect();
prop_assert!(lines.len() <= 3, "Log table should use inline format, got {} lines", lines.len());
}
#[test]
fn complex_tables_use_semicolon_separator(section in arb_complex_section()) {
let serializer = LlmSerializer::new();
let mut doc = DxDocument::new();
doc.sections.insert('d', section.clone());
let output = serializer.serialize(&doc);
let table_content = output.split('[').nth(1).unwrap_or("");
if section.rows.len() > 1 {
prop_assert!(table_content.contains("; "), "Complex table should use semicolon separator: {}", output);
}
let lines: Vec<&str> = output.lines().collect();
prop_assert!(lines.len() <= 3, "Complex table should use inline format, got {} lines", lines.len());
}
#[test]
fn simple_tables_use_comma_separator(section in arb_simple_section()) {
let serializer = LlmSerializer::new();
let mut doc = DxDocument::new();
doc.sections.insert('d', section.clone());
let output = serializer.serialize(&doc);
let table_content = output.split('[').nth(1).unwrap_or("");
if section.rows.len() > 1 {
prop_assert!(table_content.contains(", "), "Simple table should use comma separator: {}", output);
}
let lines: Vec<&str> = output.lines().collect();
prop_assert!(lines.len() <= 3, "Simple table should use inline format, got {} lines", lines.len());
}
}