use sftool_lib::utils::Utils;
use std::io::{Read, Seek, SeekFrom, Write};
use tempfile::NamedTempFile;
#[test]
fn test_hex_to_bin_single_segment() {
let hex_content = ":0400000001020304F2\n:0410000005060708D2\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x00000000);
let file_size = segment.file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 0x1004);
let mut file_data = Vec::new();
let mut file = &segment.file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(&file_data[0..4], &[0x01, 0x02, 0x03, 0x04]);
assert!(file_data[4..0x1000].iter().all(|&b| b == 0xFF));
assert_eq!(&file_data[0x1000..0x1004], &[0x05, 0x06, 0x07, 0x08]);
}
#[test]
fn test_hex_to_bin_multiple_segments() {
let hex_content = ":0400000001020304F2\n:020000040001F9\n:0400000011121314B2\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0].address, 0x00000000);
let file_size_0 = result[0].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_0, 4);
let mut file_data_0 = Vec::new();
let mut file_0 = &result[0].file;
file_0.read_to_end(&mut file_data_0).unwrap();
assert_eq!(&file_data_0, &[0x01, 0x02, 0x03, 0x04]);
assert_eq!(result[1].address, 0x00010000);
let file_size_1 = result[1].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_1, 4);
let mut file_data_1 = Vec::new();
let mut file_1 = &result[1].file;
file_1.read_to_end(&mut file_data_1).unwrap();
assert_eq!(&file_data_1, &[0x11, 0x12, 0x13, 0x14]);
}
#[test]
fn test_hex_to_bin_with_gaps() {
let hex_content = ":04000000AABBCCDDEE\n:04100000EEFF0011EE\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
println!("Number of segments: {}", result.len());
for (i, segment) in result.iter().enumerate() {
let file_size = segment.file.metadata().unwrap().len() as usize;
println!(
"Segment {}: address=0x{:08X}, size={}",
i, segment.address, file_size
);
}
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x00000000);
let file_size = segment.file.metadata().unwrap().len() as usize;
println!(
"Expected size: 0x1004 ({}), Actual size: {}",
0x1004, file_size
);
assert_eq!(file_size, 0x1004);
let mut file_data = Vec::new();
let mut file = &segment.file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(&file_data[0..4], &[0xAA, 0xBB, 0xCC, 0xDD]);
assert!(file_data[4..0x1000].iter().all(|&b| b == 0xFF));
assert_eq!(&file_data[0x1000..0x1004], &[0xEE, 0xFF, 0x00, 0x11]);
let mut file = segment.file.try_clone().unwrap();
file.seek(SeekFrom::Start(4)).unwrap();
let mut gap_data = vec![0; 0x1000 - 4];
file.read_exact(&mut gap_data).unwrap();
assert!(gap_data.iter().all(|&b| b == 0xFF));
}
#[test]
fn test_hex_to_bin_complex_multi_segment() {
let hex_content = ":100000000102030405060708090A0B0C0D0E0F1068\n:08100000111213141516171844\n:020000040001F9\n:040000002122232472\n:041000003132333422\n:020000040010EA\n:080000004142434445464748D4\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].address, 0x00000000);
let file_size_0 = result[0].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_0, 0x1008);
assert_eq!(result[1].address, 0x00010000);
let file_size_1 = result[1].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_1, 0x1004);
assert_eq!(result[2].address, 0x00100000);
let file_size_2 = result[2].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_2, 8);
let mut file_data_0 = Vec::new();
let mut file_0 = &result[0].file;
file_0.read_to_end(&mut file_data_0).unwrap();
assert_eq!(
&file_data_0[0..16],
&[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10
]
);
assert!(file_data_0[16..0x1000].iter().all(|&b| b == 0xFF));
assert_eq!(
&file_data_0[0x1000..0x1008],
&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18]
);
}
#[test]
fn test_str_to_u32() {
assert_eq!(Utils::str_to_u32("123").unwrap(), 123);
assert_eq!(Utils::str_to_u32("0x10").unwrap(), 16);
assert_eq!(Utils::str_to_u32("0b1010").unwrap(), 10);
assert_eq!(Utils::str_to_u32("0o17").unwrap(), 15);
assert_eq!(Utils::str_to_u32("1k").unwrap(), 1000);
assert_eq!(Utils::str_to_u32("1K").unwrap(), 1000);
assert_eq!(Utils::str_to_u32("1m").unwrap(), 1000000);
assert_eq!(Utils::str_to_u32("1M").unwrap(), 1000000);
}
#[test]
fn test_parse_read_file_info() {
let result = Utils::parse_read_file_info("output.bin@0x1000:0x100").unwrap();
assert_eq!(result.file_path, "output.bin");
assert_eq!(result.address, 0x1000);
assert_eq!(result.size, 0x100);
let result = Utils::parse_read_file_info("data.bin@0x20000000:1k").unwrap();
assert_eq!(result.file_path, "data.bin");
assert_eq!(result.address, 0x20000000);
assert_eq!(result.size, 1000);
assert!(Utils::parse_read_file_info("invalid_format").is_err());
assert!(Utils::parse_read_file_info("file@0x1000").is_err()); assert!(Utils::parse_read_file_info("file@invalid:0x100").is_err()); }
#[test]
fn test_parse_erase_address() {
assert_eq!(Utils::parse_erase_address("0x1000").unwrap(), 0x1000);
assert_eq!(Utils::parse_erase_address("1000").unwrap(), 1000);
assert_eq!(Utils::parse_erase_address("1k").unwrap(), 1000);
assert!(Utils::parse_erase_address("invalid").is_err());
}
#[test]
fn test_parse_erase_region() {
let result = Utils::parse_erase_region("0x1000:0x100").unwrap();
assert_eq!(result.address, 0x1000);
assert_eq!(result.size, 0x100);
let result = Utils::parse_erase_region("0x20000000:1k").unwrap();
assert_eq!(result.address, 0x20000000);
assert_eq!(result.size, 1000);
assert!(Utils::parse_erase_region("invalid_format").is_err());
assert!(Utils::parse_erase_region("0x1000").is_err()); assert!(Utils::parse_erase_region("invalid:0x100").is_err()); }
#[test]
fn test_hex_with_base_to_write_flash_files() {
let hex_content = ":020000040801F1\n:0400000001020304F2\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result =
Utils::hex_with_base_to_write_flash_files(temp_hex.path(), Some(0x10000000)).unwrap();
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x10010000);
let result_no_override =
Utils::hex_with_base_to_write_flash_files(temp_hex.path(), None).unwrap();
assert_eq!(result_no_override.len(), 1);
assert_eq!(result_no_override[0].address, 0x08010000);
}
#[test]
fn test_parse_file_info_hex_with_address() {
let hex_content = ":020000040801F1\n:0400000001020304F2\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let hex_file_path = temp_hex.path().with_extension("hex");
std::fs::copy(temp_hex.path(), &hex_file_path).unwrap();
let file_spec = format!("{}@0x10000000", hex_file_path.display());
let result = Utils::parse_file_info(&file_spec).unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].address, 0x10010000);
std::fs::remove_file(&hex_file_path).unwrap();
}
#[test]
fn test_parse_file_info_elf_with_address_error() {
let mut temp_elf = NamedTempFile::new().unwrap();
temp_elf.write_all(&[0x7F, 0x45, 0x4C, 0x46]).unwrap();
let elf_file_path = temp_elf.path().with_extension("elf");
std::fs::copy(temp_elf.path(), &elf_file_path).unwrap();
let file_spec = format!("{}@0x10000000", elf_file_path.display());
let result = Utils::parse_file_info(&file_spec);
assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("ELF files do not support")
);
std::fs::remove_file(&elf_file_path).unwrap();
}
#[test]
fn test_extended_linear_address_replacement_edge_cases() {
let hex_content1 = ":020000040000FA\n:0400000001020304F2\n:00000001FF\n";
let mut temp_hex1 = NamedTempFile::new().unwrap();
temp_hex1.write_all(hex_content1.as_bytes()).unwrap();
let result1 =
Utils::hex_with_base_to_write_flash_files(temp_hex1.path(), Some(0x12000000)).unwrap();
assert_eq!(result1[0].address, 0x12000000);
let hex_content2 = ":0200000400FFFB\n:0400000001020304F2\n:00000001FF\n";
let mut temp_hex2 = NamedTempFile::new().unwrap();
temp_hex2.write_all(hex_content2.as_bytes()).unwrap();
let result2 =
Utils::hex_with_base_to_write_flash_files(temp_hex2.path(), Some(0x34FF0000)).unwrap();
assert_eq!(result2[0].address, 0x34FF0000);
}
#[test]
fn test_hex_continuous_segments_merging() {
let hex_content = ":020000040800F2\n:0400000001020304F2\n:0400040005060708DE\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x08000000);
let file_size = segment.file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 8);
let mut file_data = Vec::new();
let mut file = &segment.file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(
&file_data,
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
);
}
#[test]
fn test_hex_different_base_continuous_segments_merging() {
let hex_content =
":020000040800F2\n:0400000001020304F2\n:020000040800F2\n:0400040005060708DE\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x08000000);
let file_size = segment.file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 8);
let mut file_data = Vec::new();
let mut file = &segment.file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(
&file_data,
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
);
}
#[test]
fn test_hex_non_continuous_segments_not_merged() {
let hex_content = ":0400000001020304F2\n:020000040001F9\n:0400000011121314B2\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0].address, 0x00000000);
let file_size_0 = result[0].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_0, 4);
assert_eq!(result[1].address, 0x00010000);
let file_size_1 = result[1].file.metadata().unwrap().len() as usize;
assert_eq!(file_size_1, 4);
}
#[test]
fn test_hex_non_aligned_large_gap_segments_are_merged() {
let hex_content = ":020000041201E7\n:0400000001020304F2\n:04FFF0001122334463\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].address, 0x12010000);
let file_size = result[0].file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 0xFFF4);
let mut file_data = Vec::new();
let mut file = &result[0].file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(&file_data[0..4], &[0x01, 0x02, 0x03, 0x04]);
assert!(file_data[4..0xFFF0].iter().all(|&b| b == 0xFF));
assert_eq!(&file_data[0xFFF0..0xFFF4], &[0x11, 0x22, 0x33, 0x44]);
}
#[test]
fn test_hex_with_base_continuous_segments_merging() {
let hex_content = ":020000040801F1\n:0400000001020304F2\n:0400040005060708DE\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result =
Utils::hex_with_base_to_write_flash_files(temp_hex.path(), Some(0x10000000)).unwrap();
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x10010000);
let file_size = segment.file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 8);
let mut file_data = Vec::new();
let mut file = &segment.file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(
&file_data,
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
);
}
#[test]
fn test_hex_with_base_non_aligned_large_gap_segments_are_merged() {
let hex_content = ":020000040801F1\n:0400000001020304F2\n:04FFF0001122334463\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result =
Utils::hex_with_base_to_write_flash_files(temp_hex.path(), Some(0x12000000)).unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].address, 0x12010000);
let file_size = result[0].file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 0xFFF4);
let mut file_data = Vec::new();
let mut file = &result[0].file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(&file_data[0..4], &[0x01, 0x02, 0x03, 0x04]);
assert!(file_data[4..0xFFF0].iter().all(|&b| b == 0xFF));
assert_eq!(&file_data[0xFFF0..0xFFF4], &[0x11, 0x22, 0x33, 0x44]);
}
#[test]
fn test_hex_continuous_with_gaps_still_merged() {
let hex_content = ":020000040800F2\n:0400000001020304F2\n:0400080005060708DA\n:04000C000A0B0C0DC2\n:00000001FF\n";
let mut temp_hex = NamedTempFile::new().unwrap();
temp_hex.write_all(hex_content.as_bytes()).unwrap();
let result = Utils::hex_to_write_flash_files(temp_hex.path()).unwrap();
assert_eq!(result.len(), 1);
let segment = &result[0];
assert_eq!(segment.address, 0x08000000);
let file_size = segment.file.metadata().unwrap().len() as usize;
assert_eq!(file_size, 16);
let mut file_data = Vec::new();
let mut file = &segment.file;
file.read_to_end(&mut file_data).unwrap();
assert_eq!(&file_data[0..4], &[0x01, 0x02, 0x03, 0x04]);
assert!(file_data[4..8].iter().all(|&b| b == 0xFF));
assert_eq!(&file_data[8..12], &[0x05, 0x06, 0x07, 0x08]);
assert_eq!(&file_data[12..16], &[0x0A, 0x0B, 0x0C, 0x0D]);
}