use hadris_block::detect::{BlockFormat, FatVariant, PartitionTableKind};
use hadris_block::partition::{gpt_partition_view, mbr_partition_view};
use hadris_block::sync::OpenVolume;
use hadris_block::{Error, part};
use hadris_fat::format::{FatFormatOptions, FatTypeSelection, FatVolumeFormatter};
const VOLUME_LEN: usize = 2 * 1024 * 1024;
fn format_fat12(
source: impl hadris_io::sync::Read + hadris_io::sync::Write + hadris_io::sync::Seek,
) {
let options = FatFormatOptions::new(VOLUME_LEN as u64).fat_type(FatTypeSelection::Fat12);
let volume = FatVolumeFormatter::format(source, options).unwrap();
drop(volume);
}
#[test]
fn opens_detected_fat_and_returns_source_borrow() {
let mut image = std::io::Cursor::new(vec![0_u8; VOLUME_LEN]);
format_fat12(hadris_io::sync::Borrowed::new(&mut image));
let volume = OpenVolume::open(&mut image, 512).unwrap();
assert_eq!(volume.format(), FatVariant::Fat12);
assert!(volume.as_fat().is_some());
let source = volume.into_inner();
assert_eq!(source.get_ref().len(), VOLUME_LEN);
}
#[test]
fn opens_fat_inside_mbr_partition_view() {
let start_lba = 1_u32;
let sector_count = (VOLUME_LEN / 512) as u32;
let entry = part::MbrPartition::new(part::MbrPartitionType::Fat12, start_lba, sector_count);
let mut table = part::MbrPartitionTable::new();
table.partitions[0] = entry;
let mbr = part::MasterBootRecord::new(table);
let mut image = std::io::Cursor::new(vec![0_u8; VOLUME_LEN + 512]);
std::io::Write::write_all(&mut image, bytemuck::bytes_of(&mbr)).unwrap();
{
let view = mbr_partition_view(&mut image, &entry, 512).unwrap();
format_fat12(view);
}
assert_eq!(
hadris_block::detect::sync::detect(&mut image, 512).unwrap(),
Some(BlockFormat::PartitionTable(PartitionTableKind::Mbr))
);
assert!(matches!(
OpenVolume::open(&mut image, 512),
Err(Error::PartitionedDisk(PartitionTableKind::Mbr))
));
let mut view = mbr_partition_view(&mut image, &entry, 512).unwrap();
let volume = OpenVolume::open(&mut view, 512).unwrap();
assert_eq!(volume.format(), FatVariant::Fat12);
}
#[test]
fn opens_fat_inside_gpt_partition_view() {
let start_lba = 2048_u64;
let sector_count = (VOLUME_LEN / 512) as u64;
let entry = part::GptPartitionEntry::new(
part::Guid::EFI_SYSTEM,
part::Guid::UNUSED,
start_lba,
start_lba + sector_count - 1,
);
let mut image = std::io::Cursor::new(vec![0_u8; (start_lba as usize * 512) + VOLUME_LEN]);
{
let view = gpt_partition_view(&mut image, &entry, 512).unwrap();
format_fat12(view);
}
let mut view = gpt_partition_view(&mut image, &entry, 512).unwrap();
let volume = OpenVolume::open(&mut view, 512).unwrap();
assert_eq!(volume.format(), FatVariant::Fat12);
}
#[test]
fn rejects_unknown_and_mismatched_formats_without_consuming_source() {
let mut unknown = std::io::Cursor::new(vec![0_u8; 1024]);
assert!(matches!(
OpenVolume::open(&mut unknown, 512),
Err(Error::UnknownFormat)
));
unknown.set_position(7);
let mut image = std::io::Cursor::new(vec![0_u8; VOLUME_LEN]);
format_fat12(hadris_io::sync::Borrowed::new(&mut image));
assert!(matches!(
OpenVolume::open_detected(&mut image, FatVariant::Fat16),
Err(Error::DetectedFormatMismatch { .. })
));
image.set_position(9);
}
#[test]
fn detects_exfat_but_rejects_unified_opening() {
let mut image = vec![0_u8; 512];
image[3..11].copy_from_slice(b"EXFAT ");
image[510..512].copy_from_slice(&[0x55, 0xaa]);
let mut image = std::io::Cursor::new(image);
image.set_position(11);
assert!(matches!(
OpenVolume::open(&mut image, 512),
Err(Error::UnsupportedFormat(BlockFormat::Fat(
FatVariant::ExFat
)))
));
assert_eq!(image.position(), 11);
}