use libmagic_rs::evaluator::evaluate_rules;
use libmagic_rs::{
Endianness, EvaluationConfig, EvaluationContext, MagicDatabase, MagicRule, OffsetSpec,
Operator, TypeKind, Value,
};
#[test]
fn test_confidence_nonzero_for_known_type() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert!(
result.confidence > 0.0,
"ELF detection should have non-zero confidence, got {}",
result.confidence
);
}
#[test]
fn test_confidence_zero_for_unknown_type() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"random unknown content").unwrap();
assert!(
(result.confidence - 0.0).abs() < f64::EPSILON,
"Unknown type should have zero confidence"
);
}
#[test]
fn test_confidence_matches_first_match() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
if let Some(first) = result.matches.first() {
assert!(
(result.confidence - first.confidence).abs() < f64::EPSILON,
"Result confidence should equal first match confidence"
);
}
}
#[test]
fn test_elf_detected_before_generic() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert!(
result.description.contains("ELF"),
"ELF should be detected, got: {}",
result.description
);
}
#[test]
fn test_pdf_detected_correctly() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"%PDF-\x00\x00\x00").unwrap();
assert!(
result.description.contains("PDF"),
"PDF should be detected, got: {}",
result.description
);
}
#[test]
fn test_png_detected_correctly() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db
.evaluate_buffer(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
.unwrap();
assert!(
result.description.contains("PNG"),
"PNG should be detected, got: {}",
result.description
);
}
#[test]
fn test_jpeg_detected_correctly() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db
.evaluate_buffer(b"\xff\xd8\xff\xe0\x00\x10JFIF\x00")
.unwrap();
assert!(
result.description.contains("JPEG") || result.description.contains("JFIF"),
"JPEG should be detected, got: {}",
result.description
);
}
#[test]
fn test_zip_detected_correctly() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"PK\x03\x04rest of zip").unwrap();
assert!(
result.description.contains("ZIP") || result.description.contains("Zip"),
"ZIP should be detected, got: {}",
result.description
);
}
#[test]
fn test_gzip_detected_correctly() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db
.evaluate_buffer(b"\x1f\x8b\x08\x00\x00\x00\x00\x00")
.unwrap();
assert!(
result.description.to_lowercase().contains("gzip"),
"GZIP should be detected, got: {}",
result.description
);
}
#[test]
fn test_evaluate_with_performance_config() {
let config = EvaluationConfig::performance();
let db = MagicDatabase::with_builtin_rules_and_config(config).unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert!(result.description.contains("ELF"));
}
#[test]
fn test_evaluate_with_comprehensive_config() {
let config = EvaluationConfig::comprehensive();
let db = MagicDatabase::with_builtin_rules_and_config(config).unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert!(result.description.contains("ELF"));
}
#[test]
fn test_evaluate_with_mime_types_enabled() {
let config = EvaluationConfig {
enable_mime_types: true,
..EvaluationConfig::default()
};
let db = MagicDatabase::with_builtin_rules_and_config(config).unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert!(
result.mime_type.is_some(),
"MIME type should be present when enabled"
);
}
#[test]
fn test_evaluate_without_mime_types() {
let config = EvaluationConfig {
enable_mime_types: false,
..EvaluationConfig::default()
};
let db = MagicDatabase::with_builtin_rules_and_config(config).unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert!(
result.mime_type.is_none(),
"MIME type should be absent when disabled"
);
}
#[test]
fn test_invalid_config_rejected() {
let config = EvaluationConfig {
max_recursion_depth: 0,
..EvaluationConfig::default()
};
let result = MagicDatabase::with_builtin_rules_and_config(config);
assert!(result.is_err(), "Zero recursion depth should be rejected");
}
#[test]
fn test_metadata_populated_for_buffer() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"\x7fELF\x02\x01\x01\x00").unwrap();
assert_eq!(result.metadata.file_size, 8);
assert!(result.metadata.evaluation_time_ms >= 0.0);
assert!(result.metadata.rules_evaluated > 0);
assert!(result.metadata.magic_file.is_none());
assert!(!result.metadata.timed_out);
}
#[test]
fn test_metadata_for_no_match() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"nothing matches this").unwrap();
assert_eq!(result.description, "data");
assert!(result.metadata.rules_evaluated > 0);
}
#[test]
fn test_evaluate_empty_buffer() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"").unwrap();
assert_eq!(result.description, "data");
}
#[test]
fn test_evaluate_single_byte_buffer() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"\x00").unwrap();
assert!(!result.description.is_empty());
}
#[test]
fn test_evaluate_all_zeros() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(&[0u8; 1024]).unwrap();
assert!(!result.description.is_empty());
}
#[test]
fn test_evaluate_all_ones() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(&[0xFF; 1024]).unwrap();
assert!(!result.description.is_empty());
}
#[test]
fn test_evaluate_partial_magic_header() {
let db = MagicDatabase::with_builtin_rules().unwrap();
let result = db.evaluate_buffer(b"\x7f").unwrap();
assert!(!result.description.is_empty());
}
#[test]
fn test_evaluate_float_rule_equal() {
let rule = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Float {
endian: Endianness::Little,
},
op: Operator::Equal,
value: Value::Float(1.0),
message: "float 1.0 detected".to_string(),
children: vec![],
level: 0,
strength_modifier: None,
};
let buffer: &[u8] = &[0x00, 0x00, 0x80, 0x3f];
let config = EvaluationConfig::default();
let mut context = EvaluationContext::new(config);
let matches = evaluate_rules(&[rule], buffer, &mut context).unwrap();
assert_eq!(matches.len(), 1, "Float equal rule should match 1.0f32 LE");
}
#[test]
fn test_evaluate_double_rule_equal() {
let rule = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Double {
endian: Endianness::Big,
},
op: Operator::Equal,
value: Value::Float(1.0),
message: "double 1.0 detected".to_string(),
children: vec![],
level: 0,
strength_modifier: None,
};
let buffer: &[u8] = &[0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let config = EvaluationConfig::default();
let mut context = EvaluationContext::new(config);
let matches = evaluate_rules(&[rule], buffer, &mut context).unwrap();
assert_eq!(matches.len(), 1, "Double equal rule should match 1.0f64 BE");
}
#[test]
fn test_evaluate_float_rule_not_equal() {
let rule = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Float {
endian: Endianness::Little,
},
op: Operator::NotEqual,
value: Value::Float(2.0),
message: "not 2.0".to_string(),
children: vec![],
level: 0,
strength_modifier: None,
};
let buffer: &[u8] = &[0x00, 0x00, 0x80, 0x3f]; let config = EvaluationConfig::default();
let mut context = EvaluationContext::new(config);
let matches = evaluate_rules(&[rule], buffer, &mut context).unwrap();
assert_eq!(
matches.len(),
1,
"Float not-equal rule should match when value differs"
);
}
#[test]
fn test_evaluate_float_rule_less_than() {
let rule = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Float {
endian: Endianness::Little,
},
op: Operator::LessThan,
value: Value::Float(2.0),
message: "less than 2.0".to_string(),
children: vec![],
level: 0,
strength_modifier: None,
};
let buffer: &[u8] = &[0x00, 0x00, 0x80, 0x3f]; let config = EvaluationConfig::default();
let mut context = EvaluationContext::new(config);
let matches = evaluate_rules(&[rule], buffer, &mut context).unwrap();
assert_eq!(
matches.len(),
1,
"Float less-than rule should match 1.0 < 2.0"
);
}
#[test]
fn test_evaluate_float_rule_no_match() {
let rule = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Float {
endian: Endianness::Little,
},
op: Operator::Equal,
value: Value::Float(2.0),
message: "should not match".to_string(),
children: vec![],
level: 0,
strength_modifier: None,
};
let buffer: &[u8] = &[0x00, 0x00, 0x80, 0x3f]; let config = EvaluationConfig::default();
let mut context = EvaluationContext::new(config);
let matches = evaluate_rules(&[rule], buffer, &mut context).unwrap();
assert!(
matches.is_empty(),
"Float equal rule should not match when value differs"
);
}