use crate::error::ParseError;
use std::io::Read;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MagicFileFormat {
Text,
Directory,
Binary,
}
pub fn detect_format(path: &Path) -> Result<MagicFileFormat, ParseError> {
let metadata = std::fs::metadata(path)?;
if metadata.is_dir() {
return Ok(MagicFileFormat::Directory);
}
let mut file = std::fs::File::open(path)?;
let mut magic_bytes = [0u8; 4];
match file.read_exact(&mut magic_bytes) {
Ok(()) => {
let magic_number = u32::from_le_bytes(magic_bytes);
if magic_number == 0xF11E_041C {
return Ok(MagicFileFormat::Binary);
}
Ok(MagicFileFormat::Text)
}
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
Ok(MagicFileFormat::Text)
}
Err(e) => Err(ParseError::IoError(e)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use std::io::Write;
#[test]
fn test_detect_format_text_file() {
let temp_dir = std::env::temp_dir();
let text_file = temp_dir.join("test_text_magic.txt");
fs::write(&text_file, "# Magic file\n0 string test Test").unwrap();
let format = detect_format(&text_file).unwrap();
assert_eq!(format, MagicFileFormat::Text);
fs::remove_file(&text_file).unwrap();
}
#[test]
fn test_detect_format_directory() {
let temp_dir = std::env::temp_dir().join("test_magic_dir");
fs::create_dir_all(&temp_dir).unwrap();
let format = detect_format(&temp_dir).unwrap();
assert_eq!(format, MagicFileFormat::Directory);
fs::remove_dir_all(&temp_dir).unwrap();
}
#[test]
fn test_detect_format_binary_mgc() {
let temp_dir = std::env::temp_dir();
let binary_file = temp_dir.join("test_binary.mgc");
let mut file = fs::File::create(&binary_file).unwrap();
file.write_all(&[0x1C, 0x04, 0x1E, 0xF1]).unwrap();
file.write_all(b"additional binary data").unwrap();
let result = detect_format(&binary_file);
assert!(result.is_ok());
match result.unwrap() {
MagicFileFormat::Binary => {
}
other => panic!("Expected Binary format, got {other:?}"),
}
fs::remove_file(&binary_file).unwrap();
}
#[test]
fn test_detect_format_nonexistent_path() {
let nonexistent = std::env::temp_dir().join("nonexistent_magic_file.txt");
let result = detect_format(&nonexistent);
assert!(result.is_err());
match result.unwrap_err() {
ParseError::IoError(e) => {
assert_eq!(e.kind(), std::io::ErrorKind::NotFound);
}
other => panic!("Expected IoError, got: {other:?}"),
}
}
#[test]
fn test_detect_format_empty_file() {
let temp_dir = std::env::temp_dir();
let empty_file = temp_dir.join("test_empty_magic.txt");
fs::write(&empty_file, "").unwrap();
let format = detect_format(&empty_file).unwrap();
assert_eq!(format, MagicFileFormat::Text);
fs::remove_file(&empty_file).unwrap();
}
#[test]
fn test_detect_format_small_file() {
let temp_dir = std::env::temp_dir();
let small_file = temp_dir.join("test_small_magic.txt");
fs::write(&small_file, "ab").unwrap();
let format = detect_format(&small_file).unwrap();
assert_eq!(format, MagicFileFormat::Text);
fs::remove_file(&small_file).unwrap();
}
#[test]
fn test_detect_format_text_with_binary_content() {
let temp_dir = std::env::temp_dir();
let binary_text_file = temp_dir.join("test_binary_text.txt");
let mut file = fs::File::create(&binary_text_file).unwrap();
file.write_all(&[0xFF, 0xFE, 0xFD, 0xFC]).unwrap();
file.write_all(b"some text").unwrap();
let format = detect_format(&binary_text_file).unwrap();
assert_eq!(format, MagicFileFormat::Text);
fs::remove_file(&binary_text_file).unwrap();
}
#[test]
fn test_magic_file_format_enum_equality() {
assert_eq!(MagicFileFormat::Text, MagicFileFormat::Text);
assert_eq!(MagicFileFormat::Directory, MagicFileFormat::Directory);
assert_eq!(MagicFileFormat::Binary, MagicFileFormat::Binary);
assert_ne!(MagicFileFormat::Text, MagicFileFormat::Directory);
assert_ne!(MagicFileFormat::Text, MagicFileFormat::Binary);
assert_ne!(MagicFileFormat::Directory, MagicFileFormat::Binary);
}
#[test]
fn test_magic_file_format_debug() {
let text_format = MagicFileFormat::Text;
let debug_str = format!("{text_format:?}");
assert!(debug_str.contains("Text"));
}
#[test]
fn test_magic_file_format_clone() {
let original = MagicFileFormat::Directory;
let cloned = original;
assert_eq!(original, cloned);
}
#[test]
fn test_magic_file_format_copy() {
let original = MagicFileFormat::Binary;
let copied = original; assert_eq!(original, copied);
}
}