use rustc_hash::{FxHashMap, FxHashSet};
use timberjack::analyzer::AnalysisResult;
#[test]
fn test_json_output_basic() {
let mut result = AnalysisResult {
matched_lines: vec![
"2025-03-21 14:00:00,123 [ERROR] NullPointerException".to_string(),
"2025-03-21 14:03:00,012 [ERROR] Connection timeout".to_string(),
],
count: 2,
time_trends: FxHashMap::default(),
levels_count: FxHashMap::default(),
error_types: FxHashMap::default(),
unique_messages: FxHashSet::default(),
deduplicated: false,
line_counts: FxHashMap::default(),
};
result.levels_count.insert("ERROR".to_string(), 2);
result
.error_types
.insert("NullPointerException".to_string(), 1);
result
.error_types
.insert("Connection timeout".to_string(), 1);
result
.unique_messages
.insert("NullPointerException".to_string());
result
.unique_messages
.insert("Connection timeout".to_string());
let json_output = serde_json::json!({
"matched_lines": result.matched_lines,
"count": result.count,
"time_trends": null,
"stats": {
"log_levels": [
{"level": "ERROR", "count": 2}
],
"error_types": [
{"error_type": "NullPointerException", "count": 1, "rank": 1},
{"error_type": "Connection timeout", "count": 1, "rank": 2}
],
"unique_messages_count": 2,
"repetition_ratio": 0.0,
"unique_messages": null
}
});
assert!(
json_output
.as_object()
.unwrap()
.contains_key("matched_lines")
);
assert!(json_output.as_object().unwrap().contains_key("count"));
assert!(json_output.as_object().unwrap().contains_key("stats"));
let stats = json_output.as_object().unwrap().get("stats").unwrap();
assert!(stats.as_object().unwrap().contains_key("log_levels"));
assert!(stats.as_object().unwrap().contains_key("error_types"));
assert!(
stats
.as_object()
.unwrap()
.contains_key("unique_messages_count")
);
assert!(stats.as_object().unwrap().contains_key("repetition_ratio"));
}
#[test]
fn test_json_structure() {
let mut result = AnalysisResult {
matched_lines: vec![
"2025-03-21 14:00:00,123 [ERROR] NullPointerException".to_string(),
"2025-03-21 15:03:00,012 [ERROR] Connection timeout".to_string(),
],
count: 2,
time_trends: FxHashMap::default(),
levels_count: FxHashMap::default(),
error_types: FxHashMap::default(),
unique_messages: FxHashSet::default(),
deduplicated: false,
line_counts: FxHashMap::default(),
};
result.time_trends.insert("2025-03-21 14".to_string(), 1);
result.time_trends.insert("2025-03-21 15".to_string(), 1);
result.levels_count.insert("ERROR".to_string(), 2);
result
.error_types
.insert("NullPointerException".to_string(), 1);
result
.error_types
.insert("Connection timeout".to_string(), 1);
result
.unique_messages
.insert("NullPointerException".to_string());
result
.unique_messages
.insert("Connection timeout".to_string());
let json_output = serde_json::json!({
"matched_lines": result.matched_lines,
"count": result.count,
"time_trends": [
{"timestamp": "2025-03-21 14", "count": 1},
{"timestamp": "2025-03-21 15", "count": 1}
],
"stats": {
"log_levels": [
{"level": "ERROR", "count": 2}
],
"error_types": [
{"error_type": "NullPointerException", "count": 1, "rank": 1},
{"error_type": "Connection timeout", "count": 1, "rank": 2}
],
"unique_messages_count": 2,
"repetition_ratio": 0.0,
"unique_messages": null }
});
assert!(json_output.is_object());
assert!(
json_output
.as_object()
.unwrap()
.contains_key("matched_lines")
);
assert!(json_output.as_object().unwrap().contains_key("count"));
assert!(json_output.as_object().unwrap().contains_key("time_trends"));
assert!(json_output.as_object().unwrap().contains_key("stats"));
}
#[test]
fn test_json_unique_messages() {
let mut result = AnalysisResult {
matched_lines: vec![
"2025-03-21 14:00:00,123 [ERROR] NullPointerException".to_string(),
"2025-03-21 14:01:00,456 [WARN] Slow database query".to_string(),
"2025-03-21 14:03:00,012 [ERROR] Connection timeout".to_string(),
],
count: 3,
time_trends: FxHashMap::default(),
levels_count: FxHashMap::default(),
error_types: FxHashMap::default(),
unique_messages: FxHashSet::default(),
deduplicated: false,
line_counts: FxHashMap::default(),
};
result
.unique_messages
.insert("NullPointerException".to_string());
result
.unique_messages
.insert("Slow database query".to_string());
result
.unique_messages
.insert("Connection timeout".to_string());
let expected_json = serde_json::json!({
"matched_lines": result.matched_lines,
"count": result.count,
"time_trends": null,
"stats": {
"log_levels": [],
"error_types": [],
"unique_messages_count": 3,
"repetition_ratio": 0.0,
"unique_messages": [
"Connection timeout",
"NullPointerException",
"Slow database query"
]
}
});
assert!(
expected_json
.as_object()
.unwrap()
.get("stats")
.unwrap()
.as_object()
.unwrap()
.get("unique_messages")
.unwrap()
.is_array()
);
}
#[test]
fn test_json_top_errors_limit() {
let mut result = AnalysisResult {
matched_lines: vec![],
count: 10,
time_trends: FxHashMap::default(),
levels_count: FxHashMap::default(),
error_types: FxHashMap::default(),
unique_messages: FxHashSet::default(),
deduplicated: false,
line_counts: FxHashMap::default(),
};
result.error_types.insert("Error1".to_string(), 10);
result.error_types.insert("Error2".to_string(), 9);
result.error_types.insert("Error3".to_string(), 8);
result.error_types.insert("Error4".to_string(), 7);
result.error_types.insert("Error5".to_string(), 6);
result.error_types.insert("Error6".to_string(), 5);
result.error_types.insert("Error7".to_string(), 4);
result.error_types.insert("Error8".to_string(), 3);
let expected_json_3_errors = serde_json::json!({
"matched_lines": [],
"count": 10,
"time_trends": null,
"stats": {
"log_levels": [],
"error_types": [
{"error_type": "Error1", "count": 10, "rank": 1},
{"error_type": "Error2", "count": 9, "rank": 2},
{"error_type": "Error3", "count": 8, "rank": 3}
],
"unique_messages_count": 0,
"repetition_ratio": 100.0
}
});
assert_eq!(
expected_json_3_errors
.as_object()
.unwrap()
.get("stats")
.unwrap()
.as_object()
.unwrap()
.get("error_types")
.unwrap()
.as_array()
.unwrap()
.len(),
3
);
let expected_json_7_errors = serde_json::json!({
"matched_lines": [],
"count": 10,
"time_trends": null,
"stats": {
"log_levels": [],
"error_types": [
{"error_type": "Error1", "count": 10, "rank": 1},
{"error_type": "Error2", "count": 9, "rank": 2},
{"error_type": "Error3", "count": 8, "rank": 3},
{"error_type": "Error4", "count": 7, "rank": 4},
{"error_type": "Error5", "count": 6, "rank": 5},
{"error_type": "Error6", "count": 5, "rank": 6},
{"error_type": "Error7", "count": 4, "rank": 7}
],
"unique_messages_count": 0,
"repetition_ratio": 100.0
}
});
assert_eq!(
expected_json_7_errors
.as_object()
.unwrap()
.get("stats")
.unwrap()
.as_object()
.unwrap()
.get("error_types")
.unwrap()
.as_array()
.unwrap()
.len(),
7
);
}