use crate::output::{EvaluationResult, MatchResult};
#[must_use]
pub fn format_text_result(result: &MatchResult) -> String {
result.message.clone()
}
#[must_use]
pub fn format_text_output(results: &[MatchResult]) -> String {
if results.is_empty() {
return "data".to_string(); }
results
.iter()
.map(|result| result.message.as_str())
.collect::<Vec<&str>>()
.join(", ")
}
#[must_use]
pub fn format_evaluation_result(evaluation: &EvaluationResult) -> String {
let filename = evaluation
.filename
.file_name()
.and_then(|name| name.to_str())
.unwrap_or("unknown");
let description = if evaluation.matches.is_empty() {
if let Some(ref error) = evaluation.error {
format!("ERROR: {error}")
} else {
"data".to_string()
}
} else {
format_text_output(&evaluation.matches)
};
format!("{filename}: {description}")
}
#[cfg(test)]
mod tests {
use cfg_if::cfg_if;
use super::*;
use crate::output::EvaluationMetadata;
use crate::parser::ast::Value;
use std::path::PathBuf;
#[test]
fn test_format_text_result() {
let result = MatchResult::new(
"ELF 64-bit LSB executable".to_string(),
0,
Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
);
let formatted = format_text_result(&result);
assert_eq!(formatted, "ELF 64-bit LSB executable");
}
#[test]
fn test_format_text_result_with_special_characters() {
let result = MatchResult::new(
"Text file with UTF-8 Unicode (with BOM) text".to_string(),
0,
Value::Bytes(vec![0xef, 0xbb, 0xbf]),
);
let formatted = format_text_result(&result);
assert_eq!(formatted, "Text file with UTF-8 Unicode (with BOM) text");
}
#[test]
fn test_format_text_output_single_result() {
let results = vec![MatchResult::new(
"PNG image data".to_string(),
0,
Value::Bytes(vec![0x89, 0x50, 0x4e, 0x47]),
)];
let formatted = format_text_output(&results);
assert_eq!(formatted, "PNG image data");
}
#[test]
fn test_format_text_output_multiple_results() {
let results = vec![
MatchResult::new(
"ELF 64-bit LSB executable".to_string(),
0,
Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
),
MatchResult::new("x86-64".to_string(), 18, Value::Uint(0x3e)),
MatchResult::new("version 1 (SYSV)".to_string(), 7, Value::Uint(0x01)),
MatchResult::new("dynamically linked".to_string(), 16, Value::Uint(0x02)),
];
let formatted = format_text_output(&results);
assert_eq!(
formatted,
"ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked"
);
}
#[test]
fn test_format_text_output_empty_results() {
let results = vec![];
let formatted = format_text_output(&results);
assert_eq!(formatted, "data");
}
#[test]
fn test_format_text_output_with_confidence_variations() {
let results = vec![
MatchResult::with_metadata(
"JPEG image data".to_string(),
0,
2,
Value::Bytes(vec![0xff, 0xd8]),
vec!["image".to_string(), "jpeg".to_string()],
95,
Some("image/jpeg".to_string()),
),
MatchResult::with_metadata(
"JFIF standard 1.01".to_string(),
6,
5,
Value::String("JFIF\0".to_string()),
vec!["image".to_string(), "jpeg".to_string(), "jfif".to_string()],
85,
None,
),
];
let formatted = format_text_output(&results);
assert_eq!(formatted, "JPEG image data, JFIF standard 1.01");
}
#[test]
fn test_format_evaluation_result_with_matches() {
let result = MatchResult::new(
"PNG image data".to_string(),
0,
Value::Bytes(vec![0x89, 0x50, 0x4e, 0x47]),
);
let metadata = EvaluationMetadata::new(2048, 1.5, 10, 1);
let evaluation = EvaluationResult::new(
PathBuf::from("/home/user/images/photo.png"),
vec![result],
metadata,
);
let formatted = format_evaluation_result(&evaluation);
assert_eq!(formatted, "photo.png: PNG image data");
}
#[test]
fn test_format_evaluation_result_with_multiple_matches() {
let results = vec![
MatchResult::new(
"ELF 64-bit LSB executable".to_string(),
0,
Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
),
MatchResult::new("x86-64".to_string(), 18, Value::Uint(0x3e)),
MatchResult::new("dynamically linked".to_string(), 16, Value::Uint(0x02)),
];
let metadata = EvaluationMetadata::new(8192, 3.2, 25, 3);
let evaluation = EvaluationResult::new(PathBuf::from("/usr/bin/ls"), results, metadata);
let formatted = format_evaluation_result(&evaluation);
assert_eq!(
formatted,
"ls: ELF 64-bit LSB executable, x86-64, dynamically linked"
);
}
#[test]
fn test_format_evaluation_result_no_matches() {
let metadata = EvaluationMetadata::new(1024, 0.8, 5, 0);
let evaluation = EvaluationResult::new(PathBuf::from("unknown.bin"), vec![], metadata);
let formatted = format_evaluation_result(&evaluation);
assert_eq!(formatted, "unknown.bin: data");
}
#[test]
fn test_format_evaluation_result_with_error() {
let metadata = EvaluationMetadata::new(0, 0.0, 0, 0);
let evaluation = EvaluationResult::with_error(
PathBuf::from("missing.txt"),
"File not found".to_string(),
metadata,
);
let formatted = format_evaluation_result(&evaluation);
assert_eq!(formatted, "missing.txt: ERROR: File not found");
}
#[test]
fn test_format_evaluation_result_filename_extraction() {
let metadata = EvaluationMetadata::new(100, 0.5, 1, 0);
let eval1 = EvaluationResult::new(
PathBuf::from("/home/user/document.pdf"),
vec![],
metadata.clone(),
);
let formatted1 = format_evaluation_result(&eval1);
assert_eq!(formatted1, "document.pdf: data");
let eval2 = EvaluationResult::new(
PathBuf::from(r"C:\Users\user\file.exe"),
vec![],
metadata.clone(),
);
let formatted2 = format_evaluation_result(&eval2);
cfg_if! {
if #[cfg(windows)] {
assert_eq!(formatted2, "file.exe: data");
} else {
assert_eq!(formatted2, r"C:\Users\user\file.exe: data");
}
}
let eval3 =
EvaluationResult::new(PathBuf::from("./test/sample.dat"), vec![], metadata.clone());
let formatted3 = format_evaluation_result(&eval3);
assert_eq!(formatted3, "sample.dat: data");
let eval4 = EvaluationResult::new(PathBuf::from("simple.txt"), vec![], metadata);
let formatted4 = format_evaluation_result(&eval4);
assert_eq!(formatted4, "simple.txt: data");
}
#[test]
fn test_format_evaluation_result_edge_cases() {
let metadata = EvaluationMetadata::new(0, 0.0, 0, 0);
let eval1 = EvaluationResult::new(PathBuf::from(""), vec![], metadata.clone());
let formatted1 = format_evaluation_result(&eval1);
assert_eq!(formatted1, "unknown: data");
let eval2 = EvaluationResult::new(PathBuf::from("/"), vec![], metadata);
let formatted2 = format_evaluation_result(&eval2);
assert_eq!(formatted2, "unknown: data");
}
#[test]
fn test_format_text_output_preserves_message_order() {
let results = vec![
MatchResult::new("First".to_string(), 0, Value::Uint(1)),
MatchResult::new("Second".to_string(), 4, Value::Uint(2)),
MatchResult::new("Third".to_string(), 8, Value::Uint(3)),
];
let formatted = format_text_output(&results);
assert_eq!(formatted, "First, Second, Third");
}
#[test]
fn test_format_text_result_handles_empty_message() {
let result = MatchResult::new(String::new(), 0, Value::Uint(0));
let formatted = format_text_result(&result);
assert_eq!(formatted, "");
}
#[test]
fn test_format_text_output_with_empty_messages() {
let results = vec![
MatchResult::new("Valid message".to_string(), 0, Value::Uint(1)),
MatchResult::new(String::new(), 4, Value::Uint(2)),
MatchResult::new("Another message".to_string(), 8, Value::Uint(3)),
];
let formatted = format_text_output(&results);
assert_eq!(formatted, "Valid message, , Another message");
}
#[test]
fn test_format_text_output_realistic_file_types() {
let pdf_results = vec![
MatchResult::new(
"PDF document".to_string(),
0,
Value::String("%PDF".to_string()),
),
MatchResult::new(
"version 1.4".to_string(),
5,
Value::String("1.4".to_string()),
),
];
assert_eq!(
format_text_output(&pdf_results),
"PDF document, version 1.4"
);
let zip_results = vec![
MatchResult::new(
"Zip archive data".to_string(),
0,
Value::String("PK".to_string()),
),
MatchResult::new("at least v2.0 to extract".to_string(), 4, Value::Uint(20)),
];
assert_eq!(
format_text_output(&zip_results),
"Zip archive data, at least v2.0 to extract"
);
let jpeg_results = vec![
MatchResult::new(
"JPEG image data".to_string(),
0,
Value::Bytes(vec![0xff, 0xd8]),
),
MatchResult::new(
"JFIF standard 1.01".to_string(),
6,
Value::String("JFIF".to_string()),
),
MatchResult::new("resolution (DPI)".to_string(), 13, Value::Uint(1)),
MatchResult::new("density 72x72".to_string(), 14, Value::Uint(72)),
];
assert_eq!(
format_text_output(&jpeg_results),
"JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72"
);
}
}