mod common;
mod common_hex;
use common::{assert_success, run_hexy, temp_dir, write_file};
use common_hex::run_hex_output;
#[test]
fn test_cli_align_length_fill() {
let dir = temp_dir("cli_align");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0xA1, 0xA2, 0xA3, 0xA4, 0xA5]);
let args = vec![
format!("/IN:{};0x1001", input.display()),
"/AF:0x00".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(norm.segments().len(), 1);
assert_eq!(norm.segments()[0].start_address, 0x1000);
assert_eq!(
norm.segments()[0].data,
vec![0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x00, 0x00]
);
}
#[test]
fn test_cli_align_address_no_separator_semantics() {
let dir = temp_dir("cli_ad_semantics");
let input = dir.join("input.bin");
let out_hex = dir.join("out_hex.hex");
let out_dec = dir.join("out_dec.hex");
write_file(&input, &[0x11, 0x22, 0x33]);
let args_hex = vec![
format!("/IN:{};0x1001", input.display()),
"/AD10".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out_hex.display().to_string(),
];
let hexfile_hex = run_hex_output(args_hex, &out_hex);
let args_dec = vec![
format!("/IN:{};0x1001", input.display()),
"/AD:10".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out_dec.display().to_string(),
];
let hexfile_dec = run_hex_output(args_dec, &out_dec);
assert_ne!(
hexfile_hex.normalized().segments()[0].data,
hexfile_dec.normalized().segments()[0].data
);
}
#[test]
fn test_cli_align_address_binary_separator() {
let dir = temp_dir("cli_ad_bin");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0x11, 0x22, 0x33, 0x44]);
let args = vec![
format!("/IN:{};0x1001", input.display()),
"/AD:0b100".to_string(),
"/AL".to_string(),
"/AF:0xEE".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(norm.segments()[0].start_address, 0x1000);
assert_eq!(
norm.segments()[0].data,
vec![0xEE, 0x11, 0x22, 0x33, 0x44, 0xEE, 0xEE, 0xEE]
);
}
#[test]
fn test_cli_align_fill_separator_and_hex_forms() {
let dir = temp_dir("cli_af_forms");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0x11, 0x22, 0x33]);
let args = vec![
format!("/IN:{};0x1001", input.display()),
"/AF:0b10101010".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(norm.segments()[0].start_address, 0x1000);
assert_eq!(norm.segments()[0].data, vec![0xAA, 0x11, 0x22, 0x33]);
}
#[test]
fn test_cli_align_fill_no_separator_equivalence() {
let dir = temp_dir("cli_af_equiv");
let input = dir.join("input.bin");
let out_hex = dir.join("out_hex.hex");
let out_dec = dir.join("out_dec.hex");
write_file(&input, &[0x11, 0x22, 0x33]);
let args_hex = vec![
format!("/IN:{};0x1001", input.display()),
"/AFCD".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out_hex.display().to_string(),
];
let hexfile_hex = run_hex_output(args_hex, &out_hex);
let args_dec = vec![
format!("/IN:{};0x1001", input.display()),
"/AF:0xCD".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out_dec.display().to_string(),
];
let hexfile_dec = run_hex_output(args_dec, &out_dec);
assert_eq!(
hexfile_hex.normalized().segments()[0].data,
hexfile_dec.normalized().segments()[0].data
);
}
#[test]
fn test_cli_align_fill_equal_separator() {
let dir = temp_dir("cli_af_eq");
let input = dir.join("input.bin");
let out_colon = dir.join("out_colon.hex");
let out_equal = dir.join("out_equal.hex");
write_file(&input, &[0x11, 0x22, 0x33]);
let args_colon = vec![
format!("/IN:{};0x1001", input.display()),
"/AF:0xCD".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out_colon.display().to_string(),
];
let hexfile_colon = run_hex_output(args_colon, &out_colon);
let args_equal = vec![
format!("/IN:{};0x1001", input.display()),
"/AF=0xCD".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/XI".to_string(),
"-o".to_string(),
out_equal.display().to_string(),
];
let hexfile_equal = run_hex_output(args_equal, &out_equal);
assert_eq!(
hexfile_colon.normalized().segments()[0].data,
hexfile_equal.normalized().segments()[0].data
);
}
#[test]
fn test_cli_cut_splits_block() {
let dir = temp_dir("cli_cut");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0, 1, 2, 3, 4, 5, 6, 7]);
let args = vec![
format!("/IN:{};0x2000", input.display()),
"/CR:0x2003,0x2".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let mut segments = hexfile.segments().to_vec();
segments.sort_by_key(|s| s.start_address);
assert_eq!(segments.len(), 2);
assert_eq!(segments[0].start_address, 0x2000);
assert_eq!(segments[0].data, vec![0, 1, 2]);
assert_eq!(segments[1].start_address, 0x2005);
assert_eq!(segments[1].data, vec![5, 6, 7]);
}
#[test]
fn test_cli_fill_region_pattern_preserves_data() {
let dir = temp_dir("cli_fill");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0x11, 0x22]);
let args = vec![
format!("/IN:{};0x3002", input.display()),
"/FR:0x3000,0x4".to_string(),
"/FP:AA55".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(
norm.read_bytes_contiguous(0x3000, 4).unwrap(),
vec![0xAA, 0x55, 0x11, 0x22]
);
}
#[test]
fn test_cli_fill_region_without_pattern_random() {
let dir = temp_dir("cli_fr_random");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0x11, 0x22]);
let args = vec![
format!("/IN:{};0x1002", input.display()),
"/FR:0x1000,0x4".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
let data = norm.read_bytes_contiguous(0x1000, 4).unwrap();
assert_eq!(data[2], 0x11);
assert_eq!(data[3], 0x22);
}
#[test]
fn test_cli_threshold_options_noop() {
let dir = temp_dir("cli_thresholds");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
write_file(&input, &[0x01, 0x02, 0x03, 0x04]);
let args = vec![
format!("/IN:{};0x0", input.display()),
"/BHFCT=10".to_string(),
"/BTFST=0x20".to_string(),
"/BTBS=0b100".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(norm.segments().len(), 1);
}
#[test]
fn test_cli_nested_chain_checksum() {
let dir = temp_dir("cli_nested_chain");
let base = dir.join("base.bin");
let merge = dir.join("merge.bin");
let out = dir.join("out.hex");
write_file(&base, &[0x10, 0x11]);
write_file(&merge, &[0xA0, 0xA1, 0xA2, 0xA3]);
let args = vec![
format!("/IN:{};0x1000", base.display()),
"/FR:0x1000,0x6".to_string(),
"/FP:AA55".to_string(),
"/CR:0x1003,0x1".to_string(),
format!("/MO:{};0x1000:0x1,0x2", merge.display()),
"/AR:0x1000-0x1004".to_string(),
"/AD4".to_string(),
"/AL".to_string(),
"/AF:0xEE".to_string(),
"/CS0:@append".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
let data = norm.read_bytes_contiguous(0x1000, 10).unwrap();
assert_eq!(
data,
vec![0x10, 0xA1, 0xA2, 0xEE, 0xAA, 0xEE, 0xEE, 0xEE, 0x05, 0xB5]
);
}
#[test]
fn test_cli_error_log_created_on_success() {
let dir = temp_dir("cli_error_log_ok");
let input = dir.join("input.bin");
let out = dir.join("out.hex");
let log = dir.join("err.log");
write_file(&input, &[0x01, 0x02]);
let args = vec![
format!("/IN:{};0x0", input.display()),
format!("/E:{}", log.display()),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let output = run_hexy(&args);
assert_success(&output);
let contents = std::fs::read_to_string(&log).unwrap_or_default();
assert!(contents.is_empty());
}
#[test]
fn test_cli_error_log_on_failure() {
let dir = temp_dir("cli_error_log_fail");
let input = dir.join("input.bin");
let log = dir.join("err.log");
write_file(&input, &[0x01, 0x02]);
let args = vec![
format!("/IN:{};0x0", input.display()),
format!("/E:{}", log.display()),
"/MT:dummy.bin".to_string(),
"/MO:dummy.bin".to_string(),
];
let output = run_hexy(&args);
assert!(!output.status.success());
let contents = std::fs::read_to_string(&log).unwrap_or_default();
assert!(!contents.is_empty());
}
#[test]
fn test_cli_address_range_reduction() {
let dir = temp_dir("cli_ar");
let base = dir.join("base.bin");
let merge = dir.join("merge.bin");
let out = dir.join("out.hex");
write_file(&base, &[0xAA, 0xAB, 0xAC, 0xAD]);
write_file(&merge, &[0xBA, 0xBB, 0xBC, 0xBD]);
let args = vec![
format!("/IN:{};0x1000", base.display()),
format!("/MO:{};0x2000", merge.display()),
"/AR:0x2000,0x4".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(norm.segments().len(), 1);
assert_eq!(norm.segments()[0].start_address, 0x2000);
assert_eq!(norm.segments()[0].data, vec![0xBA, 0xBB, 0xBC, 0xBD]);
}
#[test]
fn test_cli_address_range_reduction_start_end() {
let dir = temp_dir("cli_ar_start_end");
let base = dir.join("base.bin");
let merge = dir.join("merge.bin");
let out = dir.join("out.hex");
write_file(&base, &[0xAA, 0xAB, 0xAC, 0xAD]);
write_file(&merge, &[0xBA, 0xBB, 0xBC, 0xBD]);
let args = vec![
format!("/IN:{};0x1000", base.display()),
format!("/MO:{};0x2000", merge.display()),
"/AR:0x2000-0x2003".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let norm = hexfile.normalized();
assert_eq!(norm.segments().len(), 1);
assert_eq!(norm.segments()[0].start_address, 0x2000);
assert_eq!(norm.segments()[0].data, vec![0xBA, 0xBB, 0xBC, 0xBD]);
}
#[test]
fn test_cli_address_range_multiple_ranges() {
let dir = temp_dir("cli_ar_multi");
let base = dir.join("base.bin");
let merge = dir.join("merge.bin");
let out = dir.join("out.hex");
write_file(&base, &[0xAA, 0xAB, 0xAC, 0xAD]);
write_file(&merge, &[0xBA, 0xBB, 0xBC, 0xBD]);
let args = vec![
format!("/IN:{};0x1000", base.display()),
format!("/MO:{};0x2000", merge.display()),
"/AR:0x1000,0x2:0x2000,0x2".to_string(),
"/XI".to_string(),
"-o".to_string(),
out.display().to_string(),
];
let hexfile = run_hex_output(args, &out);
let mut segments = hexfile.segments().to_vec();
segments.sort_by_key(|s| s.start_address);
assert_eq!(segments.len(), 2);
assert_eq!(segments[0].start_address, 0x1000);
assert_eq!(segments[0].data, vec![0xAA, 0xAB]);
assert_eq!(segments[1].start_address, 0x2000);
assert_eq!(segments[1].data, vec![0xBA, 0xBB]);
}