use std::fs;
use std::path::PathBuf;
use std::process::Command;
use tempfile::TempDir;
fn hedl_bin() -> PathBuf {
let mut path = std::env::current_exe().unwrap();
path.pop(); path.pop(); path.push("hedl");
path
}
fn create_test_file(dir: &TempDir, name: &str, content: &str) -> PathBuf {
let path = dir.path().join(name);
fs::write(&path, content).unwrap();
path
}
fn run_stats(file: &PathBuf, with_tokens: bool) -> String {
let mut cmd = Command::new(hedl_bin());
cmd.arg("stats").arg(file);
if with_tokens {
cmd.arg("--tokens");
}
let output = cmd.output().expect("Failed to execute hedl stats");
assert!(
output.status.success(),
"Stats command failed:\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).unwrap()
}
#[test]
fn test_simple_object() {
let dir = TempDir::new().unwrap();
let file = create_test_file(
&dir,
"simple.hedl",
r#"%VERSION: 1.0
---
name: "John Doe"
age: 30
email: "john@example.com"
"#,
);
let output1 = run_stats(&file, false);
let output2 = run_stats(&file, false);
let output3 = run_stats(&file, false);
assert_eq!(output1, output2, "Stats output should be deterministic");
assert_eq!(output2, output3, "Stats output should be deterministic");
assert!(output1.contains("HEDL Size Comparison"));
assert!(output1.contains("JSON (minified)"));
assert!(output1.contains("JSON (pretty)"));
assert!(output1.contains("YAML"));
assert!(output1.contains("XML (minified)"));
assert!(output1.contains("XML (pretty)"));
}
#[test]
fn test_with_tokens() {
let dir = TempDir::new().unwrap();
let file = create_test_file(
&dir,
"tokens.hedl",
r#"%VERSION: 1.0
---
name: "Test Dataset"
count: 3
alpha: 1
beta: 2
gamma: 3
"#,
);
let output1 = run_stats(&file, true);
let output2 = run_stats(&file, true);
let output3 = run_stats(&file, true);
assert_eq!(output1, output2, "Token stats should be deterministic");
assert_eq!(output2, output3, "Token stats should be deterministic");
assert!(output1.contains("Estimated Tokens (LLM context)"));
assert!(output1.contains("Note: Token estimates use ~4 chars/token"));
}
#[test]
fn test_large_dataset() {
let dir = TempDir::new().unwrap();
let mut content = String::from("%VERSION: 1.0\n---\n");
for i in 0..100 {
content.push_str(&format!(
"id{}: {}\nname{}: \"Product {}\"\nprice{}: {}.99\ncategory{}: \"Category {}\"\n",
i,
i,
i,
i,
i,
i * 10,
i,
i % 10
));
}
let file = create_test_file(&dir, "large.hedl", &content);
let output1 = run_stats(&file, true);
let output2 = run_stats(&file, true);
assert_eq!(
output1, output2,
"Large dataset stats should be deterministic"
);
}
#[test]
fn test_nested_structures() {
let dir = TempDir::new().unwrap();
let file = create_test_file(
&dir,
"nested.hedl",
r#"%VERSION: 1.0
---
company: "ACME Corp"
eng_backend: 5
eng_frontend: 3
sales_enterprise: 10
sales_smb: 8
"#,
);
let output1 = run_stats(&file, true);
let output2 = run_stats(&file, true);
assert_eq!(
output1, output2,
"Nested structure stats should be deterministic"
);
}
#[test]
fn test_special_characters() {
let dir = TempDir::new().unwrap();
let file = create_test_file(
&dir,
"special.hedl",
r#"%VERSION: 1.0
---
unicode: "Hello δΈη π"
escaped: "Line 1\nLine 2\tTabbed"
quoted: "He said \"hello\""
"#,
);
let output1 = run_stats(&file, false);
let output2 = run_stats(&file, false);
assert_eq!(
output1, output2,
"Special character handling should be deterministic"
);
}
#[test]
fn test_empty_file() {
let dir = TempDir::new().unwrap();
let file = create_test_file(&dir, "empty.hedl", "");
let _result = Command::new(hedl_bin())
.arg("stats")
.arg(&file)
.output()
.expect("Failed to execute hedl stats");
}
#[test]
fn test_matrix_list() {
let dir = TempDir::new().unwrap();
let file = create_test_file(
&dir,
"matrix.hedl",
r"%VERSION: 1.0
%STRUCT: Data: [id,name,score]
---
items:@Data
|d1,Alice,95.5
|d2,Bob,87.3
|d3,Carol,92.1
",
);
let output1 = run_stats(&file, true);
let output2 = run_stats(&file, true);
assert_eq!(
output1, output2,
"Matrix list stats should be deterministic"
);
}
#[test]
fn test_no_race_conditions() {
let dir = TempDir::new().unwrap();
let file = create_test_file(
&dir,
"race.hedl",
r#"%VERSION: 1.0
---
field1: "value1"
field2: "value2"
field3: "value3"
"#,
);
use std::thread;
let file = file.clone();
let handles: Vec<_> = (0..10)
.map(|_| {
let f = file.clone();
thread::spawn(move || run_stats(&f, true))
})
.collect();
let outputs: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
for i in 1..outputs.len() {
assert_eq!(
outputs[0], outputs[i],
"Concurrent execution should produce identical results"
);
}
}